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