Da última vez quedaramos coa base da aplicación e o modelo de dados, ímos crear un Tema dende o panel de control para ir probando como manexar a base de dados e as plantillas.
Voltemos entón iniciar o servidor lanzando
python manage.py runserverdende o directorio do proxecto, feito isto poderemos acceder o panel de control a través de http://127.0.0.1:8000/admin/.
Engadamos un par de temas...
Agora, para amosar todo-los temas temos que crear unha vista, ímos ata o arquivo `meu_foro/views.py' e engadimos un método para a pantaia principal:
from django.http import HttpResponse def index(request): return HttpResponse("Funciona!")Así cando se chame a vista `index' amosará unha resposta HTTP con esa cadea, para definir a url da vista engadiremos a seguinte tupla ó `urlpatterns' no arquivo `urls.py', do directorio co nome do proxecto (neste caso `hl_django/urls.py')
urlpatterns = patterns('', # Regexp, vista url(r'^$', 'meu_foro.views.index'), ...
A regexp define as URL's dende as que se accederá a vista (neste caso as que non especifiquen unha ruta), se accedemos a http://127.0.0.1:8000/ atoparemos a resposta que programaramos.
Pero preparar a resposta directamente na vista é excesivamente tedioso, para isto Django provee dun mecanismo de plantillas (templates), para tirar partido delas crearemos un directorio `templates' (plantillas) na ruta do app, por exemplo `meu_foro/templates' e o engadimos ó `TEMPLATES_DIRS' do arquivo de configuración (`settings.py')
TEMPLATE_DIRS = ( # Engadide cadeas aquí, coma "/home/html/django_templates" ou "C:/www/django/templates". # Usade sempre barras normais '/', incluso en Windows. # Non olvidedes usar rutas absolutas, non relativas.Don't forget to use absolute paths, not relative paths. '/home/kenkeiras/hl_django/meu_foro/templates', )
Crearemos enton unha plantilla sinxela para o índice `index.html':
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>MeuForo</title> </head> <body> <h1 class="banner">MeuForo</h1> {% if temas %} <ul class="topic_list"> {% for tema in temas %} <a href="/{{ tema.id }}/"> <li>{{ tema.nome }}</li> </a> {% endfor %} </ul> {% else %} <div id="error_msg">Sen temas aínda :/</div> {% endif %} </body> </html>
Pódese ver entre '{%' e '%}' o control de fluxo que soportan as plantillas, podendo evaluar unha variable e iterar sobre ela. Ademáis podemos introducir variables usando as secuencias '{{' e '}}'
Agora, para usar as plantillas dende a vista utilizaremos a función `render_to_response' deste xeito:
from django.shortcuts import render_to_response from django.template import RequestContext def index(request): return render_to_response('index.html', context_instance=RequestContext(request))
Pero claro, a plantilla de algun lugar ten que tomar os datos, non?, podemos aforrar todo o proceso de manexar a base de dados utilizando as clases que definimos no modelo (Tema, Fio e Post):
from django.shortcuts import render_to_response from django.template import RequestContext from meu_foro.models import Tema, Fio, Post def index(request): return render_to_response('index.html', # Diccionario con 'Nome da variable': 'Valor' {'temas': Tema.objects.all()}, context_instance=RequestContext(request))
E xa amosa a lista de temas sen SQL, sen nada máis que unha chamada a unha clase
Pero o estilo queda un pouco escaso, non? ímos ver como servir arquivos estáticos dende o propio servidor (neste caso unha folla de estilos CSS :) ), se houbera que ter en conta o rendemento probablemente sería mellor usar un servidor especializado (coma nginx) para iso.
Entón, no `settings.py' definiremos dúas variables:
# Cando fagamos python manage.py collectstatics # os ficheiros irán a parar aquí STATIC_ROOT = '/home/kenkeiras/hl_django/static/' # Directorios onde se buscarán os arquivos estáticos STATICFILES_DIRS = ( '/home/kenkeiras/hl_django/meu_foro/static/', # Ollo a ',' do final )Cambiando as rutas ás adecuadas (lembrando que sexan sempre absolutas).
Para as probas creei un estilo que non entrarei a detaiar, iría en `meu_foro/static/css/style.css':
html, body{ background-color: rgb(250, 250, 250); background-repeat: repeat; margin: 0px; padding: 0px 1px 0px 1px; } .banner{ font-family: Courier; color: #FFF; text-shadow: 0px 0px 5px #000; } ::-webkit-input-placeholder { color: #666; } :-moz-placeholder { color: #666; } .return_link{ color: #222; text-decoration: none; font-size: 1.2em; font-family: Helvetica,sans-serif; } /***********************/ .post_user_info{ text-align: right; } /***********************/ .side_thread_list{ width: 25%; list-style: none; float: left; margin-left: 1px; padding: 0px; -moz-box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); } .just_thread_list{ width: 75%; list-style: none; text-align: center; margin: auto; padding: 0px; -moz-box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); } .post_list { float: right; text-align: left; width: 60%; } li > form > textarea { width: 100%; } a:first-child > .thread_item { border: none !important; } /***********************/ ul { width: 25%; list-style: none; text-align: center; margin: auto; padding: 0px; -moz-box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); box-shadow: 0px 0px 3px 3px rgba(0, 0, 0, 0.5); } ul > :first-child { border: none !important; } ul > :first-child > li { border: none !important; } li { border-top: 1px dashed #444; padding: 1ex; background-color: rgb(241, 241, 241); background-repeat: repeat; } a { color: #222; text-decoration: none; font-size: 1.8em; font-family: Helvetica,sans-serif; } li:hover{ background-color: rgb(230, 230, 230); background-repeat: repeat; }
Engadamos enton o CSS a cabeceira da plantilla do índice:
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/style.css" />Como se pode ver, a veriable '{{ STATIC_URL }}' garda a URL base dos arquivos estáticos.
Ben, voltando o foro, se queremos ver os fíos, por exemplo, a través da ruta '/<id do tema>/', para iso engadiremos a seguinte liña o `urlpatterns' no `urls.py':
url(r'^(?P\d+)/?$', 'meu_foro.views.fios'),
Isto é, as url que teñan un ou máis díxitos, seguidos ou non dun '/', resultan na vista 'meu_foro.views.fios' co id do tema coma parámetro extra, hay un par de métodos que podemos usar para atopar os datos que nos interesen:
`get_object_or_404' busca un obxecto correspondente o modelo especificado co id que pidamos (e se faia fai que o servidor web produza un erro 404, non atopado)
tema = get_object_or_404(Tema, pk=id_tema)
Tamén podemos filtrar os objectos dun modelo dado un dos campos
fios = Fio.objects.filter(tema=tema)
E só con iso, xa temos para a vista `fios'
def fios(request, id_tema): tema = get_object_or_404(Tema, pk=id_tema) fios = Fio.objects.filter(tema=tema) return render_to_response('fios.html', {'tema': tema, 'fios': fios}, context_instance=RequestContext(request))
Iso si, haberá que face-la plantilla `fios.html':
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>MeuForo</title> <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/style.css" /> </head> <body> <h3 class="banner">MeuForo-{{ tema.nome }}</h3> <ul class="just_thread_list"> <a href="/" class="return_link"><li class="thread_item">← Atrás</li></a> {% if fios %} {% for fio in fios %} <a href="/{{ tema.id }}/{{ fio.id }}/"><li>{{ fio.nome }}</li></a> {% endfor %} {% else %} <li>Sen fíos</li> {% endif %} <li> <form action="/new/{{ tema.id }}" method="POST"> Nome: <input type="text" name="nome" placeholder="Introduce o nome do fío" /><br /> <textarea name="texto" rows="5" cols="50" placeholder="O texto do primeiro post do fío"></textarea> <br /> <input type="submit" value="Novo fío!"/> {% csrf_token %} </form> </li> </ul> </body> </html>É unha plantilla coma a primeira, apenas cun formulario engadido, pero ollo, Django integra un mecanismo de seguridade contra o CSRF "de paquete", por ese motivo hay que incluir '{% csrf_token %}' en tódolos formularios, do contrario o servidor rexeitará a petición por ser sospeitosa.
Agora, para respostar a esa petición e poder probar a vista dos fíos precisamos un xeito de manexar ese POST, repetindo o proceso de ate agora engadiremos un patrón as URLs:
url(r'^new/(?P\d+)/?$', 'meu_foro.views.novo_fio'),
E unha función no `views.py':
from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from django.contrib.auth.models import User def novo_fio(request, id_tema): tema = get_object_or_404(Tema, pk=id_tema) # Se non inclúe nome ou texto, retornar a lista de fíos try: nome = request.POST['nome'] texto = request.POST['texto'] except KeyError: return fios(request, id_tema) # "Espertamos" a variable do usuario, se o é if request.user.is_authenticated(): user = request.user._wrapped if hasattr(request.user,'_wrapped') else request.user # Se non o é, creamos un anónimo (pero da clase User) else: user = User(0) # Se todo vai ben, xera un novo fío fio = Fio.objects.create(nome=nome, op=user, tema=tema, data_creacion=datetime.now()) # E nel o primeiro post post = Post.objects.create(fio=fio, usuario=user, texto=texto, data_creacion=datetime.now()) # Cando esté todo feito, redireccionamos o usuario a vista de f return HttpResponseRedirect(reverse('meu_foro.views.fios', args=(id_tema)))
Aquí podemos ver varias cousas, que o obxecto `request' mantén a sesión do usuario e datos coma as variables que passan por POST, que dispomos dun método `reverse' que dado dunha vista e uns argumentos devolve unha url e un `HttpResponseRedirect' que permite voltar un código de redirección e cal é a sintaxe para crear obxectos.
E realmente pouco máis, a vista dos post de cada fío é máis do mesmo... podería ser unha boa ocasión para practicar ;), por non deixalo a medias deixo iso tamén, inda que sen explicar.
Lista dos post, patrón da url:
url(r'^(?P\d+)/(?P \d+)/?$', 'meu_foro.views.posts'),
Vista:
def posts(request, id_tema, id_fio): tema = get_object_or_404(Tema, pk=id_tema) fio = get_object_or_404(Fio, pk=id_fio) posts = Post.objects.filter(fio=fio) return render_to_response('posts.html', {'tema': tema, 'fio': fio, 'id_fio': id_fio, 'posts': posts}, context_instance=RequestContext(request))
Plantilla:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>MeuForo</title> <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/style.css" /> </head> <body> <h3 class="banner">MeuForo-{{ tema.nome }}</h3> <ul class="side_thread_list"> <a href="/" class="return_link"><li>← Atrás</li></a> {% if fios %} {% for fio_lateral in fios %} <a href="/{{ tema.id }}/{{ fio_lateral.id }}/"><li>{{ fio_lateral.nome }}</li></a> {% endfor %} {% endif %} </ul> {% if posts %} <ul class="post_list"> {% for post in posts %} <li>{{ post.texto }} <br /><div class="post_user_info"><em class="username">{{ post.user.username }}</em></div> </li> {% endfor %} <li> <form action="/new/{{ tema.id }}/{{ id_fio }}" method="POST"> <textarea name="texto" rows="5" placeholder="E ti que dis?"></textarea><br /> {% csrf_token %} <input type="submit" value="Enviar" /> </form> </li> </ul> {% endif %} </body> </html>
O patrón de url do envío de posts:
url(r'^new/(?P\d+)/(?P \d+)/?$', 'meu_foro.views.novo_post'),
A función para crear os post:
def novo_post(request, id_tema, id_fio): fio = get_object_or_404(Fio, pk=id_fio) # Se non inclúe nome ou texto, retornar a lista de fíos try: texto = request.POST['texto'] except KeyError: return posts(request, id_tema, id_fio) # "Espertamos" a variable do usuario, se o é if request.user.is_authenticated(): user = request.user._wrapped if hasattr(request.user,'_wrapped') else request.user # Se non o é, creamos un anónimo (pero da clase User) else: user = User(0) # E nel o primeiro post post = Post.objects.create(fio=fio, usuario=user, texto=texto, data_creacion=datetime.now()) # Cando esté todo feito, redireccionamos o usuario a vista de f return HttpResponseRedirect(reverse('meu_foro.views.posts', args=(id_tema, id_fio)))
E xa está, temos un foro funcional... para a próxima como xestionar usuarios?
Saúdos
No hay comentarios:
Publicar un comentario