Django Book Español
Django Book Español
Este tutorial est basado en el "Django book". Cualquier duda, comentario o sugerencia aqu.
Antes que empieces a leer este grandioso tutorial, voy a necesitar que cumplas con unos
pequeos requisitos.
Experiencia en programacin: conceptos bsicos como variables, estructuras de control
(ejemplo: if, for, while), estructura de datos (listas, tuplas, diccionarios), clases y objetos, y
por supuesto programacin orientada a objetos.
Experiencia programando en python: Django es una coleccin de libreras escritas en
python. Entonces para desarrollar sitios usando django tienes que escribir cdigo en
python. En caso de que no sepas programar en python estas de suerte por que aprender
a programar en python es un placer, cosas que te pueden llevar varias lneas de cdigo en
otros lenguajes con python puedes hacerlo de una manera simple y en pocas lneas. Si
buscas libros para aprender python te recomiendo "python para todos" o "Dive into
python".
Qu es un web framework?
Django es un prominente miembro de una nueva generacin de web frameworks - pero que
es lo que este trmino precisamente significa?
Para contestar esta pregunta, vamos a considerar el diseo de una aplicacin web escrita en
python sin un framework. A travs de este tutorial, vamos a tomar este enfoque de trabajar
sin frameworks o atajos y despus ver como lo haramos con atajos.
Una de las maneras ms simples y directas de construir una aplicacin web escrita en python
sin utilizar ningn framework es usar CGI (Common Gateway Interface) estndar, que fue una
tcnica muy popular a finales de los 90's para desarrollar pginas web dinmicas y no
simplemente HTML esttico.
Aqu una explicacin de alto nivel de como funciona: solo crea un script en python que
imprima HTML, luego salva el script en un servidor web con la extensin ".cgi" y visita la
pagina desde tu explorador web favorito. Y eso es todo.
Aqu un ejemplo de python CGI (suponga que funciona):
#!/usr/bin/env python
import MySQLdb
print "Content-Type: text/html\n"
print "<html><head><title>Books</title></head>"
print "<body>"
print "<h1>Books</h1>"
print "<ul>"
connection = MySQLdb.connect(user='me', passwd='letmein', db='my_db')
cursor = connection.cursor()
cursor.execute("SELECT name FROM books ORDER BY pub_date DESC LIMIT 10")
for row in cursor.fetchall():
print "<li>%s</li>" % row[0]
print "</ul>"
print "</body></html>"
connection.close()
Como pueden ver lo primero que hace es imprimir Content-Type: text/html seguido de una
lnea en blanco despus imprimir algo de HTML, hace una conexin a una base de datos,
obtiene algunos registros y los imprime formateado con HTML, termina de imprimir el HTML y
cierra la conexin.
Con una pgina como esta, el escribir todo desde 0 no es necesariamente malo. Este cdigo
es simple de comprender - inclusive un programador novato puede leer estas 16 lneas de
cdigo de python y entender todo, de principio a fin. Como pueden observar no hay mucho
que aprender y no hay otro cdigo ms que leer. Adems es simple de llevar a produccin:
solo salva el cdigo en un archivo que tenga la extensin .cgi, sube el archivo al servidor
web y visita la pgina desde tu explorador.
Pero a pesar de su simplicidad, este enfoque tiene nmeros problemas y fastidios. Solo
pregntate a ti mismo las siguientes preguntas:
Qu pasa cuando mltiples partes de la aplicacin necesitan estar conectadas a la base
de datos? Seguramente ese cdigo para conectar a la base de datos no necesitara ser
duplicado en cada script CGI que hagamos. Lo ideal sera refactorizar el cdigo en una
funcin compartida para conectarnos a la base de datos.
Debe el desarrollador realmente preocuparse acerca de imprimir la linea Content-Type y
recordar cerrar la conexin a la base de datos? Este tipo de asuntos reduce la
productividad de un programador e introduce oportunidades para errores.
Qu pasa cuando el cdigo es reutilizado en mltiples ambientes, cada uno con una base
de datos y contraseas separadas? En este punto, algunas configuraciones de ambientes
especficos se vuelven esenciales.
Qu pasa cuando un diseador web sin experiencia codificando en python desea
redisear la pgina? Un carcter mal puesto y la aplicacin entera puede fallar.
Idealmente, la lgica de la pgina - el obtener registros de libros de la base de datos -
debera de estar separada del HTML que despliega la pgina, entonces el diseador puede
editar el HTML sin afectar la lgica de la aplicacin.
Estos problemas son precisamente los problemas que un web framework trata de resolver. Un
web framework provee de una infraestructura para programar tus aplicaciones, adems de
que te puedes concentrar en escribir cdigo limpio y mantenible sin tener que reinventar la
rueda. En pocas palabras eso es lo que Django hace.
El diseo del patrn MVC
Vamos a ver un rpido ejemplo que demuestra la diferencia entre el anterior y un enfoque con
un web framework. Aqu esta como ms o menos se escribira el anterior cdigo de CGI
usando Django. Y la primera cosa que notamos es que dividimos todo en 4 archivos
(models.py, views.py, urls.py) y un template HTML (latest_books.html):
# models.py (the database tables)
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=50)
pub_date = models.DateField()
# views.py (the business logic)
from django.shortcuts import render_to_response
from models import Book
def latest_books(request):
book_list = Book.objects.order_by('-pub_date')[:10]
return render_to_response('latest_books.html', {'book_list': book_list})
# urls.py (the URL configuration)
from django.conf.urls.defaults import *
import views
urlpatterns = patterns('',
(r'^latest/$', views.latest_books),
)
# latest_books.html (the template)
<html><head><title>Books</title></head>
<body>
<h1>Books</h1>
<ul>
{% for book in book_list %}
<li>{{ book.name }}</li>
{% endfor %}
</ul>
</body></html>
Otra vez, no te preocupes de la sintaxis; solo trata de entender el diseo general. La
principal cosa a notar aqu es la separacin de asuntos:
El archivo models.py contiene una descripcin de las tablas de la base de datos,
representadas por una clase. Esta clase es llamada un modelo. Usndola puedes crear,
obtener, actualizar y borrar registros en tu base de datos usando simple cdigo python en
vez de escribir una sentencia SQL que puede ser repetitiva.
El archivo views.py contiene la lgica del negocio para la pgina. La funcin latest_book es
llamada una vista.
El archivo urls.py especifica que vista debe ser llamada dado un patrn de URL. En este
caso, la URL /latest/ ser manejada por la funcin latest_books(). En otras palabras, si
tu dominio es example.com, cualquiera que visite http://example.com/latest/ va a llamar a
la funcin latest_books().
El archivo latest_books.html es un template (o plantilla) que describe el diseo de la
pgina, usando un lenguaje de template con bsicas sentencias lgicas - ejemplo {% for
book in book_list %}.
Si tomamos todas las piezas y las juntamos aproximadamente siguen un patrn llamado MVC
(Model-View-Controller).
La ventaja clave de tal enfoque es que los componentes son loosely coupled. Cada pieza de
una aplicacin web hecha con Django tiene un solo propsito clave y puede ser cambiado
independientemente sin afectar las otras piezas. Por ejemplo, un desarrollador puede cambiar
la URL de cierta parte de la aplicacin sin afectar las otras piezas de la aplicacin. Un
diseador puede cambiar el HTML de un template (o plantilla) sin tener que tocar el cdigo de
python. Un administrador de base de datos puede renombrar una tabla de la base de datos y
especificar el cambio en un solo lugar, en vez de tener que buscar y reemplazar a travs de
una docena de archivos.
La historia de Django
Antes de empezar a bucear entre ms cdigo, debemos tomar un momento para explicar la
historia de Django. Como dijimos anteriormente te vamos a mostrar como hacer las cosas sin
usar atajos, adems vas a entender mejor los atajos. Similarmente, es til entender por qu
fue creado Django, por qu el conocimiento de la historia te pondr en un contexto de
porque Django trabaja en la manera en que lo hace.
Si has estado construyendo aplicaciones web por un tiempo, probablemente estas
familiarizado con los problemas del ejemplo CGI que presentamos anteriormente. La ruta
clsica del desarrollo web va ms o menos as:
1. Escribe una aplicacin web desde 0
2. Escribe otra aplicacin web desde 0
3. Date cuenta que la aplicacin del paso 1 comparte mucho en comn con la aplicacin del
paso 2
4. Refactoriza el cdigo entonces la aplicacin 1 y 2 pueden compartir el cdigo
5. Repite los pasos del 2 al 4 varias veces
6. Date cuenta que has inventado un framework
Esto es precisamente como Django fue creado.
Django creci originalmente de aplicaciones del mundo real escritas por un equipo desarrollo
web en Lawrence, Kansas, USA. Django naci en el otoo de 2003, cuando los
programadores web del peridico "Lawrence Journal-World", Adrian Holovaty y Simon Willison,
empezaron usando python para construir aplicaciones.
El equipo "World Online", responsable de la produccin y mantenimiento de varios sitios de
noticias locales, prosperado en un ambiente de desarrollo dictado por los tiempos limites del
periodismo. Para los sitios - incluyendo LJWorld.com, Lawrence.com y KUsports.com -
periodistas (y administradores) demandaban que fueran aadidas caractersticas y
aplicaciones enteras fueran construidas en una intensamente rpida agenda, comnmente
con solo das u horas para desarrollarlo. De este modo, Simon y Adrian haban desarrollado un
web framework que les ahorraba tiempo - esa fue la nica manera en que ellos pudieron
construir aplicaciones mantenibles bajo los estrictos tiempos de entrega.
En el verano del 2005, despus de habiendo desarrollado este framework hasta un punto
donde eficientemente impulsaba la mayora de los sitios "World Online", el equipo, el cual
ahora inclua a Jacob Kaplan-Moss, decidieron liberar el framework como software de cdigo
abierto. Lo liberaron en Julio de 2005 y lo llamaron Django, en honor al guitarrista de jazz
Django Reinhardt.
Ahora, varios aos despus, Django esta bien establecido como un proyecto de software libre
con ms de diez mil usuarios y colaboradores esparcidos a travs de todo el mundo. Dos de
los desarrolladores originales de Word Online ("Los benevolentes dictadores de la vida", Adrian
y Jacob) an proveen una gua central para el crecimiento del framework, pero es mucho ms
el esfuerzo colaborativo de todo el equipo.
Esta historia es relevante por que ayuda a explicar 2 cosas clave. La primera Django es el
"lugar dulce" (sweet spot). Porque Django naci en un ambiente de noticias, ofrece varias
caractersticas (como un sitio de administracin) que son particularmente adecuados para
sitios de "contenido" - sitios como amazon.com, craigslist.org y washingtonpost.com que
ofrecen datos de una manera dinmica. - A pesar de que Django es particularmente bueno
para desarrollar ese tipo de sitios, que no lo excluye de ser una herramienta efectiva para
construir cualquier tipo de sitio web dinmico.
El segundo punto, muestra como los orgenes de Django han formado la cultura de su
comunidad de software libre. Porque Django fue extrado desde el cdigo del mundo real, en
vez de empezar como un ejercicio acadmico o producto comercial, esta sumamente
enfocado en resolver problemas de desarrollo web que los mismos desarrolladores de Django
se han enfrentado - y continan enfrentando. Como resultado, el mismo Django es
activamente mejorado en una base casi diaria.
Iniciando
Django es "solo" cdigo en python y como python corre donde sea - incluyendo celulares.
Pero este captulo solo cubre escenarios comunes para instalaciones de Django. Vamos a
asumir que estas instalndolo en un escritorio/laptop o servidor.
Despus (varios captulos ms adelante) veremos como llevar a produccin un sitio hecho
con Django.
Instalando python
En si mismo Django esta escrito completamente en python, entonces el primer paso en
instalar el framework es estar seguro que python esta instalado.
Versiones de python
El ncleo del framework Django funciona con cualquier versin de python desde la 2.3 hasta
la 2.7, dependiendo de la versin del framework las versiones ms recientes estn dejando de
dar soporte a las versiones ms antiguas de python. Por eso te recomendamos usar de
python 2.5 en adelante.
Si no estas seguro cual versin de python instalar y tienes la libertad de decidir que versin
instalar, entonces te recomendamos instalar la ultima versin de la serie 2.x. A pesar de que
Django trabaja igual con cualquier versin de python, las ltimas versiones de python tienen
mejoras de rendimiento y caractersticas adicionales del lenguaje que tal vez te guste usar en
tus aplicaciones. Adems existen add-ons (o extensiones) de terceros para Django podran
requerir versiones ms nuevas que las versiones 2.3 o 2.4
Django y python 3.x
Como saben, python esta en un proceso de transicin donde python 3.x intenta desplazar las
versiones 2.x, como ya saben cada versin de python que cambia en su primer dgito tiene
cambios importantes y adems no es compatible con versiones anteriores, por lo que muchas
aplicaciones se tienen que reescribir y eso incluye a Django.
Actualmente Django no corre completamente en python 3.x, afortunadamente esto se ha
estado planeando y desarrollando por aos. As que esperamos que muy pronto Django se
pueda correr completamente en versiones de python 3.x
Instalacin
Si estas corriendo Linux o Mac OS X, probablemente ya tienes python instalado. Solo escribe
python en tu consola (terminal o lnea de comandos) favorita. Si vez algo parecido a esto,
entonces tienes python instalado en tu sistema.
python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Si eres un usuario del sistema operativo Windows, lo ms probable es que no tengas instalado
python.
De cualquier forma, si necesitas descargar python puedes hacerlo desde aqu
http://www.python.org/download/. Las instrucciones son rpidas y fciles de seguir.
Si estas en Windows, te recomiendo bajarte el .exe o .msi ya que compilarlo puede ser algo
complicado (por lo menos en Windows). En cambio, si te encuentras en Linux y tienes un
administrador de paquetes te recomiendo usarlo, ya que regularmente los mdulos para
python tambin puedes instalarlo desde tu administrador de paquetes. Adems estos
paquetes son elegidos para que trabajen de una manera ptima con tu distribucin Linux
tambin con el tiempo obtienes actualizaciones para estos paquetes. Pero si no cuentas con
un administrador de paquetes (como apt-get, yum, pacman, ) siempre puedes descargate
el cdigo fuente del interprete, compilarlo e instalarlo.
Instalando Django
Django tiene tpicamente 2 versiones disponibles: la ltima versin oficial lanzada y la versin
experimental llamada "trunk". La versin que decidas instalar depende en tus prioridades.
Quieres una versin estable y probada de Django o quieres una versin que tenga las ltimas
caractersticas y probablemente puedas contribuir al mismo framework Django, a costo de la
estabilidad?
Nosotros te recomendamos que te pegues a las versiones oficiales (o estables), pero tambin
es importante saber que la versin "trunk" (o versin en desarrollo) existe.
Instalando la versin oficial
La ltima versin en el momento que escribo este tutorial, es la versin 1.3. Para descargar la
ltima versin puedes visitar https://www.djangoproject.com/download/. Para los usuarios
Linux que tengan administrador de paquetes pueden instalar Django desde su administrador
de paquetes, por lo regular la versin de Django que instala es una versin estable. Si no
tienes acceso a un administrador de paquetes, puedes descargar e instalar Django
manualmente. Para hacer eso visiten la pagina anterior y bajen la ltima versin, despus
corran estos comandos.
tar xzvf Django-<versin>.tar.gz #Suponiendo que estan en el directorio donde lo
descargaron
cd Django-*
sudo python setup.py install
Y listo a disfrutar Django.
Probando Django
Para saber que efectivamente instalamos Django, abrimos el intrprete dinmico de python y
escribimos lo siguiente:
import django
django.VERSION
Ajustando las bases de datos
Para trabajar con Django no es necesario tener una base de datos, pero Django tiene muchas
funciones que requieren tener una base de datos y seguramente tambin te interesar
guardar, obtener, actualizar y borrar datos. As que por eso es tan necesaria una base de
datos.
Django soporta 4 motores para base de datos:
PostgreSQL (http://www.postgresql.org/)
SQLite 3 (http://www.sqlite.org/)
MySQL (http://www.mysql.com/)
Oracle (http://www.oracle.com/)
Si no estas atado a algn sistema viejo y tienes la libertad de escoger una base de datos te
recomendamos PostgreSQL, que logra tener un buen balance entre costo, caractersticas,
velocidad y estabilidad.
Ajustar la base de datos es proceso de 2 pasos:
Primero, vas a necesitar instalar y configurar el servidor de base de datos. El proceso va
ms all del alcance de este tutorial, pero afortunadamente estos 4 motores que soporta
Django tienen mucha documentacin, una gran comunidad en cada una de estas y la
mayora de estas son fciles de instalar.
Segundo, vas a necesitar instalar una librera de python que te permita conectarte a tu
base de datos.
Si solo estas jugando o probando Django y no quieres instalar una base de datos te
recomendamos usar SQLite. SQLite es el nico motor de base de datos que soporta Django
que no requiere de ninguna instalacin, claro eso si estas usando una versin de python 2.5
en adelante.
En Windows, obtener una librera para trabajar con una base de datos puede ser frustante,
afortunadamente existe una lista de libreras para python compiladas en binarios (.exe) que
puedes conseguir aqu http://www.lfd.uci.edu/~gohlke/pythonlibs/.
Libreras de python recomendadas para conectarnos a la base de datos:
PostgreSQL: psycopg2
SQLite3: no requerido para python 2.5 en adelante.
MySQL: MySQLdb
Oracle: cx_Oracle
Empezando un proyecto
Una vez instalado python, Django y opcionalmente la librera para conectarnos a la base de
datos, puedes dar el primer paso en desarrollar una aplicacin en Django que es crear un
proyecto
Un proyecto es una coleccin de ajustes para una instancia de Django, incluyendo:
configuracin de la base de datos, opciones especficas de Django y la aplicacin.
NOTA: Para fines prcticos, no pongas tu cdigo de python en el document root.
Lo primero que vamos hacer es crear un directorio (o carpeta) y correr el siguiente comando:
django-admin.py startproject mysite
Esto va a crear una carpeta llamada mysite en tu actual directorio.
NOTA: Para los usuarios Unix django-admin.py debe se estar en el "path" de tu sistema y
adems debe de tener permisos de ejecucin esto en caso que hayas instalado Django de
manera manual. Si lo instalaste desde un administrador de paquetes probablemente el
comando no se llame django-admin.py si no django-admin . Si estas usando Windows muy
probablemente tengas que aadir python al path y luego ejecutar lo siguiente python
C:\ruta\a\django\django-admin.py mysite . De cualquier manera te recomendamos que
instales Eclipse + PyDev para que sea ms fcil trabajar en tu proyecto.
Una vez que comenzamos con nuestro proyecto tenemos una estructura ms o menos as:
mysite/
__init__.py
manage.py
settings.py
urls.py
__init__.py: un archivo que requiere python para que la carpeta mysite pueda ser
tratado como un paquete. Es un archivo vaco y generalmente no vamos aadir nada en el.
manage.py: es una utilidad de la lnea de comando, con este archivo vamos a interacturar
con el proyecto de varias maneras. Intenta con python manage.py help para darte una
idea de lo que puedes hacer. Nunca, pero nunca debes de editar este archivo.
settings.py: ajustes/configuraciones para el proyecto. chale un vistazo a los diferentes
tipos de configuraciones disponibles y a sus valores por defecto.
urls.py: las URLs del proyecto estn en este archivo. Bsicamente esto es una "tabla de
contenidos" para tu proyecto. Por el momento esta vaco.
A pesar de su tamao, estos archivos constituyen una aplicacin completamente funcional.
Corriendo el servidor de desarrollo
La mayora del tiempo vamos a correr el servidor de desarrollo para ver como va quedando
nuestro proyecto.
El servidor de desarrollo de Django (tambin llamado "runserver" en honor al comando que lo
lanza) es un servidor web integrado y ligero que puedes usar para desarrollar tu sitio. Esta
incluido en la instalacin de Django entonces puedes desarrollar rpidamente tu sitio, sin
estar teniendo que lidiar con la configuracin de un servidor web de produccin (ejemplo
Apache) hasta que este listo para la produccin. El servidor de desarrollo vigila tu cdigo y
automticamente lo recarga, haciendo fcil para tu cambiar el cdigo sin la necesidad de
reiniciar nada.
Para iniciar el servidor, muvete al directorio de tu proyecto (mysite) y ejecuta el siguiente
comando:
python manage.py runserver
Despus deberas de ver algo como esto:
Validating models...
0 errors found
Django version 1.2.3, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
Esto lanza el servidor localmente en el puerto 8000, accesible solo para las conexiones de tu
propia computadora. Ahora que esta corriendo, visita http://127.0.0.1:8000/ con tu
navegador web favorito. Entonces vas a ver "Welcome to Django" en una pagina de tono
azul.
Tambin pueden cambiar el puerto por donde escucha el servidor web de la siguiente manera:
python manage.py runserver 8080
Inclusive pueden admitir otras conexiones que no sean de su computadora:
python manage.py runserver 0.0.0.0:8000
Obviamente este servidor web rpido y ligero es solo para hacer pruebas de manera local y
no se debe de usar para produccin, ya que no esta probado tan intensivamente como otros
servidores web.
Vistas y URLconfs
Tu primera pgina hecha con Django: Hola Mundo!
Una vez que ya tenemos instalado Django podemos empezar a jugar. Como primera pgina
vamos hacer el popular "Hola mundo!"
Vamos a ver un ejemplo sencillo de como hacer un hola sin un framework:
1. Creas un archivo de texto plano que contenga "Hola mundo!"
2. Guardas el archivo con el nombre hola.html
3. Finalmente, lo subes a tu servidor web y listo.
En este proceso hemos identificado 2 piezas claves para el desarrollo de pginas. La primera
es el contenido del archivo en este caso "Hola mundo" y la URL
(http://www.example.com/hola.html o tal vez http://www.example.com/files/hola.html si lo
pusiste en un subdirectorio). Con Django, tambin debes de especificar estas 2 cosas, pero
de una manera diferente. El contenido de un archivo es renderizado por una funcin llamada
vista, y la URL es especificada por un URLconf. Primero vamos a escribir la funcin "hola".
Tu primera vista
En el directorio mysite que hiciste con el comando django-admin startproject, tienes un
archivo llamado views.py. Este mdulo de python contendr las vistas que haremos durante
esta entrada. Nota que cuando abras este archivo por primera vez estar vaco. Adems, a
Django no le importa como se llame este archivo pero por convencin lo mantendremos como
views.py.
Nuestra vista "Hola mundo" es muy simple, aqu esta un ejemplo de como sera nuestra
funcin:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hola mundo")
Vamos a leer el cdigo lnea por lnea:
Primero, importamos la clase HttpResponse, la cual reside en el mdulo django.http.
Necesitamos importar esta clase porque la vamos a usar ms adelante en nuestro cdigo.
Segundo, definimos una funcin llamada hello - la funcin vista.
Cada funcin vista recibe al menos un parmetro llamado request por convencin. Este es un
objeto que contiene informacin acerca de la peticin web que fue disparada por esta vista,
adems este objeto es una instancia de la clase django.http.HttpRequest. En este ejemplo no
vamos a hacer nada con request, pero este siempre debe de ser el primer parmetro en
cualquier vista.
Nota que el nombre de la funcin no importa, no tiene que ser llamada de cierta manera para
que Django la reconozca. La estamos llamando hello, porque el nombre claramente indica la
esencia de la vista, pero tambin pudo ser llamada hola_hermoso_bello_mundo o algo igual de
repulsivo.
La funcin es un simple "one-liner": Simplemente regresa un objeto de la clase HttpResponse
que has inicializado con el texto "Hola mundo".
Aqu la principal leccin es esta: una vista es una funcin de python que toma como primer
parmetro un objeto HttpRequest y regresa una instancia de la clase HttpResponse. Para que
una funcin pueda ser una vista Django, necesita hacer estas 2 cosas. (Claro que hay
excepciones y vamos a ver estas excepciones despus).
Si el lector es lo suficiente agudo pudo darse cuenta que este es bsicamente el modelo
cliente-servidor.
Tu primer URLconf
Hasta es te punto si corres python manage.py runserver otra vez, todava vas a ver el
mensaje "It worked", sin pista alguna de nuestro "Hola mundo". Y esto es porque nuestro
proyecto mysite an no sabe de la existencia de nuestra vista hello. Necesitamos decirle a
Django que estamos activando esta vista en una URL especfica. (Continuando con la
analoga de los archivos HTML estticos, en este momento todava no hemos subido nuestro
archivo al servidor.) Para enlazar una vista a una URL en particular usando Django, usamos
un URLconf.
Un URLconf es como una tabla de contenidos para tu sitio hecho con Django. Bsicamente es
una tabla de relaciones donde describe que funcin debe de ser llamada cada vez que visitan
cierta URL. Por ejemplo cuando alguien visite foo llama a la vista foo_view(), que vive en el
mdulo views.py.
Cuando ejecutaste django-admin startproject, el script creo un URLconf por ti
automticamente: el archivo urls.py. Por defecto se ve ms o menos as:
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^mysite/', include('mysite.foo.urls')),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
# (r'^admin/', include(admin.site.urls)),
)
Este archivo urls.py por defecto incluye algunas caractersticas comentadas usadas por
Django, para activar estas caractersticas es fcil solo tienes que descomentar las lneas
necesarias y listo. Si ignoramos los comentarios entonces tenemos algo ms o menos as.
from django.conf.urls.defaults import *
urlpatterns = patterns('',
)
Vamos a analizar lnea por lnea el cdigo. La primera lnea importa todos los objetos de el
mdulo django.conf.urls.defautls, la cual es la infraestructura de los URLconfs de Django.
Esto tambin incluye una funcin llamada patterns. La segunda lnea llama a la funcin
patterns y salva su resultado en una variable llamada urlpatterns. La funcin patterns se le
pasa un solo argumento - una cadena vaca. (Esto se puede usar como prefijo pero lo
veremos ms adelante)
El principal punto a notar aqu es la variable urlpatterns, el cual Django espera encontrar en
nuestro mdulo de URLconfs. Esta variable define las relaciones entre las URLs y las vistas
que manejan estas URLs. Por defecto la URLconf esta vaca. Adems si el URLconf esta vaco
Django asume que acabas de crear tu proyecto mostrando el mensaje "It worked!".
Ahora lo nico que tienes que hacer es aadir una tupla para definir la relacin entre una URL
y una vista.
Ejemplo:
from django.conf.urls.defaults import *
from mysite.views import hello
urlpatterns = patterns('',
('^hello/$', hello),
)
Nosotros hemos quitado los comentarios para brevedad, pero si quieres puedes dejarlos.
Hicimos 2 cambios:
Primero, importamos la funcin hello de nuestro mdulo mysite.views. Segundo, aadimos la
lnea ('^hello/$', hello), a urlpatterns. A esta lnea la vamos a llamar URLpattern.
Ahora vamos a discutir un poco sobre la sintaxis de un URLpattern porque no es obvio a
primera vista. A pesar de que queremos hacer coincidir la URL /hello/, el patrn se ve un
poco diferente a eso. Vamos a ver por qu:
Django quita los slash (/) del frente de la URL antes de que la cheque con los URLpatterns.
Esto significa que nuestro URLpattern no incluye los slash del frente entonces /hello/
quedara hello/.
Los patrones incluyen un circunflejo (^) y el signo de dolar ($). Esto son caracteres
especiales de expresiones regulares que tienen un significado especial: El circunflejo (^)
significa que "el patrn requiere coincidir desde el inicio de la cadena", por el otro lado el
signo de dolar ($) significa que "requiere que el patrn coincida con el final de la cadena".
Este concepto se puede explicar mejor con un ejemplo. Si en vez del patrn ^hello/$
hubiramos usado ^hello/ (sin el signo de dolar al final), entonces cualquier URL que empiece
con /hello/ coincidira, tal como /hello/foo y /hello/bar y no solamente /hello/. Igualmente
si hubiramos usado la expresin hello/$ sin el circunflejo al principio entonces coincidira
cualquier cadena que termine en hello/ como /foo/bar/hello/. Si no hubiramos usado ni el
signo de dolar ni el circunflejo solo hello/ entonces coincidira cualquier cadena que contenga
hello/ tal como /foo/hello/bar. Y es por eso que tan importante usar el circunflejo y el signo
de dolar.
La mayora de los URLpatterns empezarn con un circunflejo y terminarn con signo de dolar
pero es importante saber que tambin podemos hacer patrones mas sofisticados.
Hasta este momento te estars preguntando qu pasara si alguien hiciera una peticin a la
URL /hello. Porque nuestro URLpattern requiere un slash al final, esa URL no coincidira. Sin
embargo, por defecto cualquier peticin que no coincida con URLpattern y no termine con un
slash va ser redireccionado a la misma URL con un slash al final. (Esto es regulado por la
variable APPEND_SLASH que puedes encontrar en tu archivo de configuracin settings.py.)
Otra cosa que deberas notar acerca de los URLconfs es que hemos pasado la funcin hello
como un objeto sin llamar a la funcin. Esto es una caracterstica clave de python (y de
muchos otros lenguajes dinmicos): las funciones son objetos de primera clase, lo que
significa que puedes pasarlos como si fuera cualquier otra variable.
Para probar nuestros cambios en el URLconf, inicia el servidor de desarrollo de Django, como
lo hiciste anteriormente corriendo el comando (python manage.py runserver). Si lo dejaste
corriendo esta bien, no es necesario que lo reinicies, el servidor automticamente detecta
cambios en tu cdigo y recarga lo necesario, entonces no necesitas reiniciar el servidor para
ver cambios. El servidor esta corriendo en la direccin http://127.0.0.1:8000/, entonces
abre tu navegador web favorito y entra a http://127.0.0.1:8000/hello/. Entonces debes de
ver el texto "Hola mundo" - la salida de tu vista hello.
Felicidades! Has hecho tu primera pagina web con Django.
Nota: Expresiones regulares
Expresiones regulares (o regexes) son una manera compacta de especificar patrones en el
texto. Mientras las URLconfs de django permiten expresiones regulares arbitrarias para una
poderosa coincidencia de patrones en la URL, probablemente solo uses un pocas
expresiones en la practica. Aqui hay una pequea seleccin de las expresiones mas
usadas:
Expresin Coincide
. (dot) Cualquier carcter.
\d Un solo dgito decimal.
[A-Z] Cualquier cracter entre A y Z (uppercase)
[a-z] Cualquier cracter entre a y z (lowercase)
[A-Za-z] Cualquier cracter entre a y z (case-insensitive)
+ Uno o mas de la expresin previa (ejemplo: \d+ coincide uno o ms
dgitos)
[^/]+ Uno o mas caracteres hasta (y sin incluir) el slash.
? Cero o una de la expresin previa (ejemplo: \d? coincide cero o un dgito)
* Cero o mas de la expresin previa (ejemplo: \d* coincide cero, uno o mas
de un dgito).
{1,3} Entre 1 y 3 (inclusive) de la expresin previa (ejemplo: \d{1,3} coincide
uno, dos o tres dgitos)
Para mas expresiones regulares ver http://www.djangoproject.com/r/python/re-module/.
Una nota rpida acerca de errores 404
Hasta este punto, nuestra URLconf define un solo URLpattern: El nico que maneja las
peticiones de la URL /hello/. Pero que pasa cuando lanzas una peticin a una URL
diferente?
Para averiguarlo, trata de correr el servidor de desarrollo de django y visitar alguna URL que
no tengas en el URLconf, por ejemplo http://127.0.0.1:8000/goodbye/ o
http://127.0.0.1:8000/hello/subdirectory/, o incluso http://127.0.0.1:8000/. Entonces debes
de poder ver el mensaje Page not found (pagina no encontrada, ver la siguiente Figura).
Django muestra este mensaje por que la URL que estas tratando de acceder no esta definida
en el URLconf.
La utilidad de esta paginan va mas all de un bsico mensaje de error 404. Adems te dice
que URLconf esta usando django y cada patrn de la URLconf. A partir de esa informacin,
deberas de ser capaz de deducir por que la peticin a URL arrojo un error 404.
Naturalmente, esta es informacin sensible y pretendido solo para ti, el desarrollador web. Si
este fuera un sitio en produccin en Internet, seguramente no querras que esta informacin
sea expuesta al publico. Por esta razn, la pagina Page not found va a ser mostrada
solamente si tu proyecto django esta en modo debug. Ms tarde vamos a explicar como
desactivar el modo debug. Por ahora, solo necesitas saber que cada proyecto django esta en
modo debug la primera vez que es creado, y si el proyecto no esta en modo debug, django
mostrara un diferente mensaje.
Una nota rpida acerca del sitio raz
Como explicamos en la ultima seccin, vas a ver un mensaje de error 404 en el sitio raz --
http://127.0.0.1:8000/. Django no aade nada magicamente al sitio raz; de cualquier manera
esa URL no es ningn caso especial. Esta en tus manos (o mejor dicho en tus dedos) asignar
ese URLpattern, justo como cualquier otro URLpattern en tu URLconf.
El URLpattern que coincide con el sitio raz es exactamente intuitivo, aunque, vale la pena
mencionarlo. Cuando ests listo para implementar la vista para tu sitio raz, usa el URLpattern
^$, que coincide una cadena vaca. Por ejemplo:
from mysite.views import hello, my_homepage_view
urlpatterns = patterns('',
('^$', my_homepage_view),
# ...
)
Como Django Procesa una Peticin
Antes de continuar con nuestra segunda funcin vista, vamos a pausar un momento y
aprender un poco mas acerca de como django trabajo. Especficamente, cuando ves el
mensaje Hello Word una vez que visitas http://127.0.0.1:800/hello/ en tu navegador web
favorito, Qu es lo que hace django detrs de las escenas?
Todo empieza con el archivo settings. Cuando tu corres python manage.py runserver, el script
va y busca por un archivo llamado settings.py. En la misma carpeta que manage.py. Este
archivo contiene todo tipo de configuraciones para este proyecto en particular, todas las
configuraciones estan en mayusculas (o mejor dicho en uppercase): TEMPLATE_DIRS,
DATABASE_NAME, etc. La configuracin ms importante es una llamada ROOT_URLCONF.
ROOT_URLCONF le dice a django que modulo de python debe de ser usado para el URLconf de
este sitio.
Recuardas cuando django-admin startproject creo los archivos settings.py y urls.py? El
archivo settings.py autogenerado contiene una configuracin ROOT_URLCONF que por
defecto apunta a un archivo urls.py tambien autogenerado. Abre settings.py y mira por ti
mismo; mas o menos debe verse de la siguiente manera:
ROOT_URLCONF = mysite.urls
Esto corresponde al archivo mysite/urls.py.
Cuando una peticion entra por alguna URL en particular -- por ejemplo, una peticin para
/hello/ -- django carga el URLconf que especifa la configuracin ROOT_URLCONF. Despus
checa cada URLpattern en el URLconf, en orden, comparando la URL con los patrones uno por
uno, hasta que encuentre uno que coincida. Cuando encuentra uno que coincide, llama a la
funcin asociada a ese patrn, pasando un objeto HttpRequest como primer parmetro.
(Nosotros vamos a cubrir mas especificamente HttpRequest ms adelante).
Como vimos en nuestro primer ejemplo, una funcin vista debe de regresar un HttpResponse.
Una vez que la vista regresa el objeto HttpResponse, django se encarga del resto, convierte el
objeto a una respuesta HTTP apropiada, con cabeceras y el cuerpo. En resumen:
1. Una peticin entra por /hello/.
2. Django determina que URLconf usar en base a la configuracin ROOT_URLCONF.
3. Django pasa por todos los URLpatterns en el URLconf y busca el primero que coincida
con /hello/.
4. Si encuentra una coincidencia, entonces llamada la funcin vista asociada.
5. La funcin vista regresa un HttpResponse.
6. Django convierte ese objeto HttpResponse a una apropiada respuesta HTTP, la cual
resulta en una pagina web.
Ahora sabes lo bsico de como funciona las paginas hechas con Django. Es bastante simple,
realmente -- solo escribes funciones vista y las asocias a URLs via URLconfs.
Tu segunda vista: Contenido dinmico
Nuestra vista Hola mundo fue instructiva en demostrar lo bsico de como funciona Django,
pero no fue un ejemplo de una pagina web dinmica porque el contenido de la pagina es
siempre el mismo. Cada vez que visitas /hello/, vas a ver lo mismo; es como si fuera un
archivo estatico HTML.
Para nuestra segunda vista, vamos a crear algo mas dinmico, -- una pagina web que
muestre la fecha y hora actual. Esto va a ser un agradable y simple paso, porque no
envuelve ninguna base de datos o datos de entrada del usuario -- solo despliega la fecha y
hora del servidor. Es tan solo un poco mas emocionante que el Hello world, pero va a
demostrar mas conceptos que nuestro ejemplo pasado.
Esta vista necesita 2 cosas: Calcular la fecha y hora actual y regresar un HttpResponse
conteniendo ese valor. Si has tenido experiencia con python, probablemente sabes que
python incluye el modulo datetime para calcular fechas. Aqu esta como lo vamos a usar:
>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2008, 12, 13, 14, 9, 39, 2731)
>>> print now
2008-12-13 14:09:39.002731
Esto es lo suficientemente simple y no tiene nada que ver con Django. Es solo cdigo escrito
en python. (Nosotros queremos hacer nfasis que es solo cdigo python vs. cdigo que es
especifico de django. Como estas aprendiendo python, nosotros queremos que seas capaz de
usar tu conocimiento en otros proyectos que usen python pero que no necesariamente usen
django.)
Para hacer que nuestra vista despliege la fecha y hora actual, lo unico que necesitamos
hacer es enganchar datetime.datetime.now() en la vista y regresar un objeto HttpResponse.
Aqu esta como quedara:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
Al igual como nuestra vista hello, esta funcin debe de residir en views.py. Nota que hemos
escondido la vista hello en este ejemplo por cuestiones de brevedad, pero as es como se
veria nuestro views.py hasta ahora:
from django.http import HttpResponse
import datetime
def hello(request):
return HttpResponse("Hello world")
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
(De aqu en adelante, no vamos a mostrar cdigo de ejemplos anteriores, excepto cuando
sea necesario. As que deberas de ser capaz de distinguir el nuevo cdigo vs. el viejo cdigo
a partir del contexto de la lectura.)
Ahora vamos a ver paso por paso los cambios que hemos hecho con views.py para poner la
vista current_datetime.
Hemos aadido import datetime al principio del mdulo para poder calcular fechas.
La nueva funcin current_datetime calcula la fecha y hora actual, como un objeto
datetime.datetime y lo guarda en una variable local llamada now.
La segunda lnea de cdigo de nuestra vista, construye la respuesta HTML usando
format-string de python (o formateo de cadenas de python). El %s en el string
representa un placeholder (o parmetro de sustitucin) y el simbolo de % despus
del string significa Reemplaza el %s con el valor de la variable now. La variable now es
tcnicamente un objeto datatime, no un string, pero el formato %s lo convierte a un
string, cuya representacin es algo como 2008-12-13 14:09:39.002731. Entonces
este sera el resultado en nuestro string que contiene HTML <html><body>It is now
2008-12-13 14:09:39.002731.</body></html>.
(Si, nuestro HTML es invlido, pero estamos tratando de mantener el ejemplo simple y
corto).
Finalmente, la vista regresa un objeto HttpResponse que contiene la respuesta
generada -- tal como lo hicimos en la vista hello.
Despues de aadir nuestro cdigo a views.py, aadir el URLpattern a urls.py para decirle a
django qu URL debera de manejar esta vista. Algo como /time/ tendra ms sentido:
from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime
urlpatterns = patterns('',
('^hello/$', hello),
('^time/$', current_datetime),
)
Nosotros hicimos 2 cambios aqu. Primero importamos la funcin current_datetime al inicio del
modulo. Segundo, y ms importante, aadimos un URLpattern que mapea la URL /time/ a
nuestra nueva vista. Te empiezas a acostumbrar a esto?
Con la vista escrita y el URLconf actualizado, encendemos el runserver y visitamos
http://127.0.0.1:8000/time/ en tu navegador favorito y entonces deberas de ponder ver la
fecha y hora actual.
La zona horaria de django
Dependiendo de tu computadora, la fecha y la hora pueden estar unas horas desfasadas.
Esto es por que django es consiente de la zona horaria y por defecto la zona horaria es
America/Chicago. (Bueno, tena que tener alguna una zona horaria por defecto y esa zona
horaria es donde residen los desarrolladores originales). Si tu vives en alguna otra parte,
probablemente vas a querer cambiarla y lo puedes hacer desde el archivo settings.py.
URLconfs y Loose Coupling
Ahora es un buen momento para remarcar una filosofa clave detrs del URLconfs y de django
en general: El principio de loose coupling (o asociacin difusa). Para ponerlo simple, loose
coupling es un enfoque de desarrollo de software que aprecia la importancia de hacer piezas
intercambiables de software. Si dos piezas de software son loosely coupled (o asociadas
difusamente), entonces los cambios hechos a una pieza de software tiene un efecto poco o
nulo sobre la otra pieza de software.
Las URLconfs de django son un buen ejemplo de este principio en la prctica. En una
aplicacin web hecha con django, las definiciones de las URLs y las vista son llamadas loosely
coupled (difusamente asociadas); eso es, la desicin de poder cambiar la URL y la vista
indistintamente y que ninguna de las 2 partes se vea afectada por la otra.
Por ejemplo, consideremos nuestra vista current_datetime. Si nosotros queremos cambiar la URL
para la aplicacin -- digamos, moverla de /time/ a /current-time/ -- nosotros podemos hacer un
rpido cambio en el URLconf, sin tenernos que preocupar acerca de la vista. Similarmente, si
nosotros quisieramos cambiar la vista -- alterando su lgica de algn modo -- nosotros podramos
hacer eso sin tener que alterar la URL a la cual est sujeta.
Adems, si nosotros queremos exponer la fecha actual en diferentes URLs, nosotros podemos
hacer esto fcilmente editando el URLconf, sin tener que tocar nada del cdigo de la vista.
Es este ejemplo, nuestra vista current_datetime esta disponible en dos URLs. Es un ejemplo
artificial, pero esta tcnica puede volverse bastante til.
urlpatterns = patterns('',
('^hello/$', hello),
('^time/$', current_datetime),
('^another-time-page/$', current_datetime),
)
URLconfs y vistas estn difusamente asociados y vamos a continuar haciendo nfasis a la
importancia de esta filosofa a travs de este libro.
Tu tercera vista: URLs dinmicas
En nuestra vista current_datetime, el contenido de la pagina -- la fecha y hora actual -- es
dinamica, pero la URL (/time/) fue estatica. En la mayora de las aplicaciones web dinamicas,
una URL contiene parametros que afectan la salida de la pgina. Por ejemplo, una tienda de
libros online tal vez le de a cada libro su propia URL, como /books/243/ y /books/81196/.
Vamos a crear una tercera vista que despliege la fecha y hora actual desplazado por un
cierto nmero de horas. El objetivo es hacer un sitio de tal manera que la pgina
/time/plus/1/ despliege la fecha y hora una hora en el futuro, la pgina /time/plus/2/
despliege la fecha y hora 2 horas en el futuro, la pgina /time/plus/3/ despliege la fecha y
hora 3 horas en el futuro y as sucesivamente.
Un novato tal vez pensara en codificar una vista separada para cada desplazamiento, la cual
tal vez resulte en un URLconf como este:
urlpatterns = patterns('',
('^time/$', current_datetime),
('^time/plus/1/$', one_hour_ahead),
('^time/plus/2/$', two_hours_ahead),
('^time/plus/3/$', three_hours_ahead),
('^time/plus/4/$', four_hours_ahead),
)
Claramente, este tipo de pensamiento es defectuoso. No solamente resulta en una sera de
funciones redundantes, si no que adems la aplicacin esta fundamentalmente limitada a
soportar solo un rango predefinido de horas -- uno, dos, tres o cuatro horas. Si nosotros
decidimos crear una pagina que despliegue el tiempo cinco horas en el futuro, tendramos que
crear una vista separada y agregar a nuestro URLconf el URLpatter necesario, adems de la
duplicacin. Entonces necesitamos hacer un poco de abstraccin aqu.
Un poco acerca de pretty URLs
Si tu has experimentado en otra plataforma de desarrollo web, tal como PHP o Java, tal vez
estes pensando Hey, vamos a usar un query string! -- algo como /time/plus?hours=3, en
cual las horas seran designadas por el parmetro hours en el query string de la URL (la
parte despues del ?).
Tu puedes hacer eso con django (y te lo vamos en el capitulo 7), pero una de las filosofias
que forman el nucleo de django es que la URL debe de ser hermosa. La URL /time/plus/4/
is mucho mas limpia, simple, legible, fcil de pasarsela a alguien y mas bonita que un query
string. Pretty URLs (o URLs bonitas o amigables) son una caracterstica de la calidad de
una aplicacin Web.
El sistema de URLconf de django fomenta el uso de pretty URLs haciendo ms fcil el uso
de pretty URLs que no hacerlo.
Entonces, Como diseamos nuestra aplicacin para que maneje desplazamientos arbitrarios?
La clave es usar una wildcard (o comodn) en el URLpatterns. Como mencionamos
anteriormente, un URLpattern es una expresin regular; y por lo tanto, podemos usar el
patrn \d+ para coincidir uno o mas dgitos:
urlpatterns = patterns('',
# ...
(r'^time/plus/\d+/$', hours_ahead),
# ...
)
(Nosotros estamos usando #... para implicar que pueden haber otros URLpatterns que
nosotros quitamos de este ejemplo por cuestiones de simplicidad.)
Este nuevo URLpatter va a coincidir cualquier URL como /time/plus/2/, /time/plus/25/ o
incluso /time/plus/100000000000/. Pensadolo bien, vamos a limitar el desplazamiento maximo
permitido a 99 horas. Esto significa que queremos permitir solo uno o dos dgitos -- y en
nuestra expresin regular esto se traducira como \d{1,2}.
(r'^time/plus/\d{1,2}/$', hours_ahead),
Nota
Cuando construimos aplicaciones web, siempre es importante considerar hasta la ms
descabellada entrada posible, y decidir si nuestra aplicacin debera soportar esa entrada o no.
Nosotros decidimos limitar el desplazamiento a 99 horas y evitarnos posibles entradas
descabelladas.
Un detalle importante que tenemos que introducir aqu es el carcter r antes del inicio del
string que contiene la expresin regular. Esto le dice a python que el string es un raw string
(o cadena cruda) -- cuyo contenido no debe de interpretar los backslashes (o diagonales
inversas \). En los string normales, los backslashes son usados para representar caracteres
especiales -- tal como en el string \n, el cual es un string de un solo carcter que contiene
una nueva linea. Cuando aades una r antes de una cadena lo que haces es convertir esa
cadena un raw string (o cadena cruda), y entonces python no aplica el escapado de
caracteres especiales. -- entonces, r\n es ahora un string de 2 caracteres que contiene
un literalmente un backslash (\) y una n. Existe una colisin natural entre el uso de
backslashes en los string normales de python y los backslashes que necesita las expresiones
regulares, por eso recomendamos fuertemente el uso de raw strings (cadenas crudas)
cuando estas escribiendo alguna expresin regular. Desde ahora, todos los URLpatterns sern
raw strings.
Ahora que hemos designado una wildcard (comodn) para la URL, necesitamos una manera de
pasar los datos que capture esa wildcard a nuestra vista, para que podamos usar una sola
vista para un numero arbitrario de horas desplazadas. Nosotros hacemos esto poniendo
parentesis al rededor del patrn que queremos capturar en el URLpattern. En el caso de
nuestro ejemplo, nosotros queremos salvar cualquier numero que fue introducido en la URL,
entonces vamos a poner parentesis al rededor de el \d{1,2}, de la siguiente manera:
(r'^time/plus/(\d{1,2})/$', hours_ahead),
Si estas familiarizado con expresiones regulares, entonces te sentiras como en casa;
Nosotros estamos parntesis para capturar los datos que coincidan en el texto.
El URLconf, incluyendo las 2 vistas previas, quedara as:
from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead
urlpatterns = patterns('',
(r'^hello/$', hello),
(r'^time/$', current_datetime),
(r'^time/plus/(\d{1,2})/$', hours_ahead),
)
Una vez hecho esto, vamos a escribir nuestra vista hours_ahead.
Orden de codificacin
En este ejemplo, nosotros escribimos primero el URLpattern y despues la vista, pero en los
ejemplos previos, nosotros escribimos primero la vista y despus el URLpattern. Cual
tcnica es mejor?
Bueno, cada desarrollador es diferente.
Si eres el tipo de persona que ve todo de manera muy general, tal vez tenga ms sentido
para ti escribir todas las URLpatterns en tu aplicacin al mismo tiempo, al inicio de tu
proyecto y luego codificar las vistas. Esto tiene la ventaja de darte una lista de tareas que
debes de hacer y esencialmente defines los parmetros requeridos por las vistas que vas a
necesitar escribir.
Si por lo contrario eres ms del tipo de programador que le gusta empezar de abajo hacia
arriba, tal vez prefieras escribir tus vistas primero y despus anclarlas a una URL. Esto
tambin esta bien.
Al final, usas la tcnica a la que mejor se adapte tu cerebro. Ambos enfoques son
perfectamente vlidos.
hours_ahead is muy similar a la vista current_datetime que escribimos antes, con una
diferencia clave: toma un argumento extra, el numero de horas a desplazar. Aqu esta como
se vera el cdigo:
from django.http import Http404, HttpResponse
import datetime
def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
Vamos a explorar este cdigo lnea por lnea:
La vista, hours_ahead, toma dos parmetros: request y offset, que son la peticin y el
desplazamiento respectivamente.
request es un objeto HttpRequest, justo como en las vistas hello y
current_datetime. Lo vamos a decir otra vez: Cada vista siempre toma un
objeto HttpRequest como su primer parmetro.
offset es el string capturado por los parentesis en el URLpattern. Por ejemplo,
si la URL fuera /time/plus/3/, entonces el offset (desplazamiento) sera la
cadena 3. Si la URL fuera /time/plus/21/, entonces el offset sera la cadena
21. Nota que los valores capturados siempre son strings y no enteros,
incluso si el string esta compuesto de puros digitos, como 21.
(Tecnicamente, los valores capturados siempre sern objetos Unicode, no
planas y simples bytestrings, pero no te preocupes sobre esto, es solo una
aclaracin por el momento.)
Nosotros decidimos a nuestra variable offset, pero tu puedes nombrarla como
tu quieras, claro siempre y cuando sea un identificador vlido en python. El
nombre de la variable no importa; todo lo que importa es el segundo
argumento, despus de request. (Tambin es posible usar un keyword (palabra
clave o argumento opcional), en vez de un argumento posicional en el URLconf.
Vamos a cubrir esto en Vistas y URLconfs avanzados)
La primera cosa que hacemos en la vista es llamar a la funcin int() con offset como
parmetro. Esto trata convertir el string a un entero.
Nota que python va a lanzar una excepcin ValueError si llamas a int() con un
parmetro que no puede ser convertido a un entero, como por ejemplo el string foo.
En este ejemplo si encontramos una excepcin de tipo ValueError, nosotros lanzamos
una excepcin django.http.Http404, la cual, como te puedes imaginar, resulta en una
pgina de error 404 Page not found.
Lectores astutos se preguntaran: Como podramos alcanzar el caso donde ValueError
es lanzado, si de cualquier modo, dada la expresin regular en nuestro URLpattern --
(\d{1,2}) -- captura solamente digitos, y por lo tanto offset solo va a ser un string
compuesto de digitos? La respuesta es, no vamos a hacerlo, por que el URLpattern
provee una modesto pero util nivel de validacin, pero aun as seguimos checando por
el error ValueError en caso que esta vista llege a ser llamada de alguna otra manera.
Adems es una buena practica implementar vistas de tal manera que no tengan que
hacer ninguna suposicin de los parametros que van a recibir. Loose coupling
(asociacin difusa), recuerdas?
En la siguiente lnea de vista, nosotros calculamos la fecha y hora actual y aadimos
el nmero apropiado de horas. Como ya hemos visto datatime.datetime.now() de la
vista current_datetime; el nuevo concepto aqu es que puedes ejecutar aritmtica de
fecha/hora creando un objeto datetime.timedelta y sumandolo con un objeto
datetime.datetime. Nuestro resultado es almacenado en la variable dt.
Esta lnea tmbien muestra por que llamamos a int() con offset -- la funcin
datetime.timedelta requiere que el parmetro hours sea un entero.
Luego, construimos el HTML que desplegara esta vista, tal como hicimos en la vista
current_datetime. Una pequea diferencia en esta lnea comparada con los anteriores
string format (formateos de cadenas) que hemos hecho, es que ahora hay dos
simbolos %s en el string y una tupla de valores a insertar (offset, dt).
Finalmente, regresamos un objeto HttpResponse con el HTML.
Con esa vista y URLconf escrita, iniciamos el servidor de desarrollo de django (a menos que
ya este corriendo), y visitamos http://127.0.0.1:8000/time/plus/3/ para verificar que
funcione. Luego probamos http://127.0.0.1:8000/time/plus/5/. Despues
http://127.0.0.1:8000/time/plus/24/. Finalmente, visitamos
http://127.0.0.1:8000/time/plus/100/ para verificar que el patron en tu URLconf solo acepte
numeros de uno o dos digitos; Django debera desplegar el error Page not found (pagina no
encontrada) en este caso, justo como lo vimos en la seccin Una nota rpida acerca de las
errores 404. La URL http://127.0.0.1:8000/time/plus/ (sin ninguna hora designada) tambien
debera de arrojar un error 404.
Las paginas de errores amigables de django
Toma un momento para admirar la fina aplicacin que hemos hecho hasta el momento
ahora vamos a romperla! Vamos a introducir deliberadamente errores en nuestro archivo
views.py, comentando las lineas de offset = int(offset) en la vista hours_ahead:
def hours_ahead(request, offset):
# try:
# offset = int(offset)
# except ValueError:
# raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
Carga el servidor de desarollo y entra a /time/plus/3/. Vas a ver una pgina de error con una
sustancial cantidad de informacin, incluyendo un mensaje de error TypeError desplegado al
mero inicio: "unsupported type for timedelta hoyrs component: unicode"
Qu paso? Bueno, la funcin datetime.timedelta espera que el parmetros hours sea un
entero, y nosotros comentamos un poco de cdigo que convertia offset en un entero. Eso
causo que datetime.timedelta lanzara el TypeError. Es el tpico error que le ocurre a cualquier
programador en algn punto.
El punto de este ejemplo fue demostrar las paginas de error de Django. Tomate tiempo para
explorar la pagina de error y conocer un poco la variada informacin que ofrece.
Aqu hay un par de cosas que notar:
Al principio de la pgina, vas a ver informacin clave acerca de la excepcin: el tipo
de la excepcin, los parametros de la excepcin (en este caso el mensaje
"unsupported type"), el archivo en el que fue lanzada la excepcin y el nmero de
linea.
Debajo de la informacin clave de la excepcin, la pgina muestra todo el "traceback"
(el traceback es el rastro de origen de la excepcin). Esto es similar al estandar
traceback de la consola interactiva de python, excepto que esta es mas interactiva.
Para cada nivel ("frame") en la pila, django despliega el nombre del archivo, el nombre
de la funcin o metodo, el nmero de linea y el cdigo fuente de esa lnea.
Da click en la lnea "source code" (en gris oscuro) y vas a ver varias lineas desde
antes y despus de la lnea erronea, para darte un contexto.
Da click en "Local vars" debajo de cualquier frame para ver una tabla de todas las
variables locales y sus valores, en ese frame en el momento justo donde la excepcin
fue lanzada. Esta informacin de depuracin puede ser de gran ayuda.
Nota el link "Switch to copy-and-paste view" (cambia a la vista para copiar y pegar),
debajo de la cabecera con el texto "Traceback". Da click en ese link y el traceback va
a cambiar a una versin alternativa que puede ser copiada y pegada fcilmente. Usa
esto cuando quieras compartir el traceback de la excepcin con otras personas para
obtener soporte tcnico -- como en el canal IRC de django o en la lista de correos de
django.
Siguiente, la seccin "Request Information" (informacin de la peticin) incluye
informacin acerca peticin web que ingresa: GET, POST, COOKIE, meta informacin,
tales como cabeceras CGI y FILES. El apendice G tiene una completa referencia de
toda la informacin que contiene un objeto Request.
Debajo de la seccin "Request information", la seccin de "Settings" (ajustes) lista
todos los ajustes de esta particular instalacin de django. (Nosotros ya mencionamos
ROOT_URLCONF, y vamos a mostrarte varios ajustes de django a lo largo del libro.
Todos los ajustes son cubiertos en detalle en el apndice D.)
La pgina de error de django es capaz de desplegar mas informacin en ciertos casos
especiales, tal como el caso de error de sintaxis. Vamos a ver eso mas adelante, cuando
hablemos sobre el sistema de "templates" (plantillas) de django.
Por ahora, descomenta las lineas de offset = int(offset) para que la vista funcione
apropiadamente otra vez. Eres el tipo de programador que le gusta depurar con la ayuda de
sentencias print cuidadosamente colocadas? Si es as, puedes usar la pagina de error de
django para hacer eso. -- solo que sin las sentencias print. En cualquier punto de tu vista,
temporalmente inserta assert False para lanzar una pgina de error. Entonces, puedes ver
las variables locales y estado del programa. Aqu hay un ejemplo, usando la vista
hours_ahead:
def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
assert False
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
Finalmente, es obvio que mucha de esta informacin es sencible -- expone todas las tripas
de tu cdigo y de la configuracin de django -- y sera tonto mostrar esta informacin en
Internet. Una persona maliciosa puede intentar usar ingeniera-inversa en tu aplicacin web
para hacer cosas sucias. Por esa razn, la pgina de error de django solo se muestra cuando
la aplicacin esta en modo debug (depuracin). Vamos a ensearte a como desactivar en
"Django en produccin". Por ahora, solo sabes que cada proyecto django esta en modo debug
automaticamente cuando lo empiezas. (Te suena familiar? la pgina de error "Page not
found", descrita al inicio de este captulo, trabaja de la misma manera.)
Plantillas (capitulo 4, zerokillex)
En el captulo anterior, pudo haber notado algo especial en cmo se devolvi el texto en
nuestro ejemplo de la vista. Es decir, el HTML fue incrustrado directamente en el cdigo
python como sigue:
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
Aunqu esta tcnica fue conveniente para el propsito de la explicacin en como las vistas
trabajan, no es una buena idea incrustrar HTML directamente en nuestras vistas. He aqu por
qu:
Cualquier cambio en el diseo de la pgina requiere un cambio en el cdigo python. El
diseo de un sitio web tiende a cambiar con ms frecuencia que el cdigo subyacente
de python, por lo que sera conveniente si el diseo pudiera cambiar sin necesidad de
modificar el cdigo python.
Escribir cdigo python y disear en HTML son dos diciplina distintas, y muchos
entornos profesionales de desarrollo web dividen estas responsabilidades entre
distintas personas (o incluso entre departamentos). Los diseadores y autores
HTML/CSS no deberan estar obligados editar el cdigo python para llevar a cabo su
trabajo.
Es ms eficiente si los programadores pueden trabajar el cdigo python y los
diseadores trabajar con la plantilla al mismo tiempo, en lugar de una persona esperar
que otro termine editar un solo archivo que contiene python y HTML.
Por estas razones, es mucho ms limpio y mantenible separar el diseo de pginas del cdigo
python. Esto lo podemos lograr con el sistema de plantillas de Django, el cual discutiremos en este
captulo.
Fundamentos del sistema de plantillas
Una plantilla Django es una cadena de texto destinado a separar la presentacin del documento
de sus datos. Una plantilla define los marcadores de posicin y varios fragmentos de la lgica
bsica (etiquetas de plantillas) que regulan como el documento debe ser mostrado. Usualmente,
las plantillas son utilizadas para producir HTML, pero las plantillas Django son igualmente capaces
de generar cualquier formato basado en texto.
Comencemos con una plantilla de ejemplo. La siguiente plantilla Django describe una pgina HTML
que agradece a una persona al completar una orden con una empresa. Piense en ello como un
modelo de carta:
<html>
<head><title>Ordering notice</title></head>
<body>
<h1>Ordering notice</h1>
<p>Dear {{ person_name }},</p>
<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:"F j, Y" }}.</p>
<p>Here are the items you've ordered:</p>
<ul>
{% for item in item_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% if ordered_warranty %}
<p>Your warranty information will be included in the packaging.</p>
{% else %}
<p>You didn't order a warranty, so you're on your own when
the products inevitably stop working.</p>
{% endif %}
<p>Sincerely,<br />{{ company }}</p>
</body>
</html>
Esta plantilla es un HTML bsico con algunas variables y etiquetas vertidas en el. Analicemos sus
partes:
Cualquier texto rodeado por un par de llaves (por ejemplo, {{ person_name }}) es una
variable. Esto significa insertar el valor de la variable con el nombre dado. (Cmo indicamos
los valores de las variables? Ms adelante hablaremos de ello.)
Cualquier texto que esta rodeado de una llave y el signo de porcentaje (por ejemplo, {%
if ordered_warranty %}) es una etiqueta de plantilla. La definicion de una etiqueta es
bastante amplio: una etiqueta le dice al sistema de plantilla haz algo.
Esta plantilla de ejemplo contiene una etiqueta for ({% for item in item_list %}) y una
etiqueta if ({% if ordered_warranty %}).
Una etiqueta for funciona muy similar a la declaracin for en python, permitiendo iterar
sobre cada elemento de una secuencia. Una etiqueta if, como se puede esperar, acta
como una declaracin lgica. En este caso particular, la etiqueta comprueba si el valor de
la variable ordered_warranty evala a True. Si lo hace, el sistema de plantilla mostrar
todo entre {% if ordered_warranty %} y {% else %}. Si no, el sistema de plantilla mostrar
todo entre {% else %} y {% endif %}. Tenga en cuenta que {% else %} es opcional.
Finalmente, el segundo prrafo de esta plantilla contiene un ejemplo de un filtro, que es la
forma ms conveniente de modificar el formato de una variable. En este ejemplo, {{
ship_date|date:F j, Y }}, estamos pasando la variable ship_date al filtro date,
indicando al filtro date el argumento F j, Y. El filtro date formatea las fechas en un
formato dado, segn lo especificado en el argumento. Los filtros estan enlazado utilizando
el carcter de barra vertical (|), como referencia a las tuberas (pipe) en Unix.
Cada plantilla Django tiene acceso a varias etiquetas y filtros incorporadas, de los cuales muchos
se discuten en las prximas secciones. El Apndice F contiene una lista completa de etiquetas y
filtros, y es recomendable familiarizarse con la lista para que conozca lo que es posible. Tambin
es posible crear sus propios filtros y etiquetas; ms detalles en el captulo Plantillas avanzadas.
Utilizando el sistema de plantilla
Entremos en el sistema de plantillas de Django para que puedas ver cmo funciona pero
todava no vamos a integrarlo en la vista que creamos en el captulo anterior. Nuestro objetivo
aqu es mostrar cmo el sistema funciona, independientemente del resto de Django. (Dicho de
otro modo: habitualmente utilizars el sistema de plantilla dentro de una vista de Django, pero
queremos dejar claro que el sistema de plantilla es slo una librera de python que se puede
utilizar en cualquier lugar, no slo en las vistas de Django.)
Esta es la forma ms bsica que puedes utilizar el sistema de plantilla de Django en el cdigo
python:
1. Crear un objeto Template proporcionando el cdigo puro de la plantilla como una cadena
de texto.
2. Invocar el mtodo render() del objeto Template con un conjunto de variables (el contexto).
Esto devuelve una plantilla completamente representada como una cadena, con todas sus
variables y etiquetas de plantilla evaluada de acuerdo al contexto.
En cdigo, as es como luce:
>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Adrian'})
>>> print t.render(c)
My name is Adrian.
>>> c = template.Context({'name': 'Fred'})
>>> print t.render(c)
My name is Fred.
La siguientes secciones describen cada parte con mucho ms detalle.
Creando objetos Template
La forma ms fcil de crear un objeto Template es con una instancia directamente de ella. La clase
Template reside en el mdulo django.template, y el constructor toma un argumento, el cdigo puro
de la plantilla. Veamos en el intrprete interactivo de python cmo esto funciona en cdigo.
Desde el directorio del proyecto mysite creado por django-admin.py startproject (como explic
en el captulo 2: Iniciando), escribe python manage.py shell para iniciar el intrprete interactivo.
Un smbolo especial de python
Si usted antes ha utilizado python, puede que se pregunte por qu estamos utilizando
python manage.py shell en lugar de slo python. Ambos comandos inician el intrprete
interactivo de python, pero el comando manage.py shell tiene una importante distincin:
antes de iniciar el intrprete, este le dice a Django cul archivo de configuracin utilizar.
Muchas partes de Django, incluyendo el sistema de plantilla, se basan en tus
configuraciones, y no sers capaz de utilizarlos a menos que el framework conozca cual
configuracin utilizar.
Si tienes curiosidad, he aqu cmo funciona en el trasfondo. Django busca en el entorno
una variable llamada DJANGO_SETTINGS_MODULE, que debe estar declarada a la ruta de
importacin de tu settings.py. Por ejemplo, DJANGO_SETTINGS_MODULE podra estar
establecido a mysite.settings, asumiendo que mysite esta en la ruta de python.
Cuando se ejecuta python manage.py shell, el comando se encarga de establecer
DJANGO_SETTINGS_MODULE por ti. Le animamos a que utilice python manage.py shell en
estos ejemplos con el fin de minimizar la cantidad de ajustes y configuraciones que
tienes que hacer.
A medida que se familiarice con Django, es posible que dejes de usar manage.py shell y
configures manualmente DJANGO_SETTINGS_MODULE en tu archivo .bash_profile u otro
archivo de configuracin del entorno de la consola.
Repasemos algunos conceptos bsicos del sistema de plantilla:
>>> from django.template import Template
>>> t = Template('My name is {{ name }}.')
>>> print t
Si usted est siguiendo de forma interactiva, vers algo como esto:
<django.template.Template object at 0xb7d5f24c>
El 0xb7d5f24c ser diferente cada vez, y no es relevante; es propio de python (la identidad del
objeto Template en python, si te interesa saberlo).
Cuando se crea un objeto Template, el sistema de plantilla compila el cdigo crudo en uno interno,
de forma optimizada, listo para reproducir. Pero si el cdigo de tu plantilla incluye errores de
sintaxis, la invocacin a Template() levantar una excepcin de TemplateSyntaxError.
>>> from django.template import Template
>>> t = Template('{% notatag %}')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
...
django.template.TemplateSyntaxError: Invalid block tag: 'notatag'
El trmino block tag aqu se refiere a {% notatag %}. Block tag y template tag son
sinnimos. El sistema levanta una excepcin TemplateSyntaxError en cualquiera de los siguientes
casos:
Etiquetas no vlidas
Argumentos no vlidos para etiquetas vlidas
Filtro no vlido
Argumentos no vlidos para filtros vlidos
Sintaxis de plantilla no vlido
Etiquetas sin cerrar (para etiquetas que requieren etiquetas de cierre)
Interpretando plantillas
Una vez obtienes un objeto Template, puedes pasarle datos indicando un contexto. Un contexto
es simplemente un conjunto de nombres de variables en la plantilla y sus valores asociados. Una
plantilla las utiliza para llenar sus variables y evaluar sus etiquetas.
Un contexto es representado en Django por la clase Context, que reside en el mdulo
django.template. Su constructor toma un argumento opcional: un diccionario de claves asociadas
a valores. Ejecute el mtodo render() del objeto Template con el contexto para llenar la plantilla:
>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
u'My name is Stephane.'
Un aspecto que debemos destacar aqu es que el valor a devolver de t.render(c) es un objeto
Unicode no es una cadena normal de python. Lo puedes confirmar por la u en frente de la
cadena. Django utiliza los objetos Unicode en lugar de cadenas normales en todo el framework. Si
entiendes las repercusiones de ello, s agradecido por los detalles sofisticados que Django hace
en el trasfondo para que funcione. Si no entiendes las repercusiones, no te preocupes por ahora,
slo sepa que el soporte de Django para Unicode hace que sea relativamente indoloroso el
soporte de tus aplicaciones con una mplia variedad de conjuntos de caracteres ms all de los
bsicos A-Z del confunjo de caracteres ASCII.
Diccionarios y contextos
Un diccionario en python es una correspondencia entre claves conocidas y valores de las
variables. Un contexto es similar a un diccionario, pero un contexto proporciona funcionalidades
adicionales, como se explica en el captulo Plantillas avanzadas.
Los nombres de variables deben comenzar con una letra (A-Z o a-z) y puede contener letras,
dgitos, guiones, y puntos. (Los puntos son un caso especial, en un momento llegaremos.) Los
nombres de variables se distinguen entre minsculas y maysculas. He aqu un ejemplo de la
compilacin y representacin de una plantilla, utilizando una plantilla similar a la del comienzo de
este captulo.
>>> from django.template import Template, Context
>>> raw_template = """<p>Dear {{ person_name }},</p>
...
... <p>Thanks for placing an order from {{ company }}. It's scheduled to
... ship on {{ ship_date|date:"F j, Y" }}.</p>
...
... {% if ordered_warranty %}
... <p>Your warranty information will be included in the packaging.</p>
... {% else %}
... <p>You didn't order a warranty, so you're on your own when
... the products inevitably stop working.</p>
... {% endif %}
...
... <p>Sincerely,<br />{{ company }}</p>"""
>>> t = Template(raw_template)
>>> import datetime
>>> c = Context({'person_name': 'John Smith',
... 'company': 'Outdoor Equipment',
... 'ship_date': datetime.date(2009, 4, 2),
... 'ordered_warranty': False})
>>> t.render(c)
u"<p>Dear John Smith,</p>\n\n<p>Thanks for placing an order from Outdoor
Equipment. It's scheduled to\nship on April 2, 2009.</p>\n\n\n<p>You
didn't order a warranty, so you're on your own when\nthe products
inevitably stop working.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment
</p>"
Analicemos por parte cada una de las instrucciones:
Primero, importamos la clase Template y Context, que ambos conviven en el mdulo
django.template.
Guardamos el texto crudo de nuestra plantilla en la variable raw_template. Tenga en
cuenta que usamos triple comillas para designar la cadena, ya que admite mltiples lneas;
en cambio, las cadenas entre comillas simples no admite mltiples lneas.
A continuacin, creamos un objeto Template, t, proporcionando raw_template al
constructor Template.
Importamos el mdulo datetime de la librera estndar de python, ya que lo necesitamos
en la siguiente sentencia.
Luego creamos el objeto c de Context. El constructor Context toma un diccionario de
python que asocia las variables con valores. Aqu, por ejemplo, especificamos que
person_name es John Smith, company es Outdoor Equipment, y as sucesivamente.
Finalmente, invocamos el mtodo render() en nuestro objeto Template pasndole el
contexto. Este devuelve la plantilla analizada es decir, se reemplazan las variables de la
plantilla con el valor actual de las variables, y ejecuta las etiquetas de la plantilla.
Note que el prrafo You didnt order a warranty fue mostrado porque la variable
ordered_warranty fue evaluado como falso (False). Tambin notar que la fecha, April 2,
2009, es mostrada de acuerdo a la cadena de formato F j, Y. (Ms adelante explicaremos
la cadena de formato para el filtro date.)
Si eres nuevo en python, se estar preguntando por qu esta salida incluye el carcter
salto de lnea o new line (\n) en lugar de mostrar el salto. Es debido a una situleza
en el intrprete interactivo de python: la invocacin de t.render(c) devuelve una cadena, y
por defecto el intrprete interactivo muestra la representacin de la cadena, en lugar del
valor impreso de la cadena. Si deseas ver la cadena con los saltos de lneas como
realmente deben en lugar de los caracteres \n, utilice la sentencia print: print t.render(c).
Estos son los fundamentos del uso del sistema de plantillas en Django: slo escribe una plantilla
en texto, crea un objeto Template, crea un contexto Context, e invoca el mtodo render().
Mltiples contextos, la misma plantilla
Una vez tengas un objeto Template, se puede procesar mltiples contextos a travs de este. Por
ejemplo:
>>> from django.template import Template, Context
>>> t = Template('Hello, {{ name }}')
>>> print t.render(Context({'name': 'John'}))
Hello, John
>>> print t.render(Context({'name': 'Julie'}))
Hello, Julie
>>> print t.render(Context({'name': 'Pat'}))
Hello, Pat
Siempre que quieras procesar mltiples contextos utilizando la misma plantilla como en el ejemplo,
es ms eficiente crear un objeto Template una vez, y luego invocar mltiples veces render():
# Mal uso
for name in ('John', 'Julie', 'Pat'):
t = Template('Hello, {{ name }}')
print t.render(Context({'name': name}))
# Buen uso
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
print t.render(Context({'name': name}))
El parseo de plantillas en Django es bastante rpido. En el trasfondo, la mayora del parsing se
produce a travs de una simple expresin regular. Este esta marcado por una gran diferencia con
los motores de plantillas basado en XML, que incurren en el exceso de parsing XML y tiende ser
por magnitud ms lento que el sistema de plantilla de Django.
Bsqueda de variable en el contexto
En los ejemplos hasta el momento, hemos pasado simples valores en los contextos
mayormente strings, en adicin a un datetime.date. Sin embargo, el sistema de plantillas maneja
elegantemente estructuras de datos ms complejos, tales como listas, diccionarios, y objetos
personalizados.
El punto clave para navegar sobre estructuras de datos complejos en las plantillas de Django es
el carcter de punto (.). Utilizando el punto puedes accesar a las claves de diccionarios, atributos,
mtodos, o los ndices de un objeto.
Esto se ilustra mejor en varios ejemplos. Por ejemplo, supongamos que pasamos un diccionario a
una plantilla. Para accesar los valores de ese diccionario por su clave, utilizamos el punto:
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'Sally is 43 years old.'
Del mismo modo, el punto permite el acceso a los atributos de un objeto. Por ejemplo, el objeto
datetime.date contiene los atributos year, month, y day, con el punto puedes acceder estos
atributos en la plantilla de Django:
>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
1993
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{
date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
u'The month is 5 and the year is 1993.'
Este otro ejemplo utiliza una clase personalizada, demostrando que con el punto te permite
acceder a objetos arbitrarios:
>>> from django.template import Template, Context
>>> class Person(object):
... def __init__(self, first_name, last_name):
... self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name
}}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
u'Hello, John Smith.'
Los puntos tambin pueden acceder a mtodos en los objetos. Por ejemplo, en python cada string
tiene los mtodos upper() e isdigit(), y puedes invocarlos en las plantillas de Django utilizando la
misma sintaxis de punto:
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
u'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
u'123 -- 123 -- True'
Note que no se incluye los parntesis en la invocacin de los mtodos. Adems, no es posible
pasar argumentos a los mtodos; solo puedes invocar mtodos que no requieren argumentos.
(Luego explicarmos esta filosofa en este captulo.)
Finalmente, los puntos tambin se utilizan para accesar los ndices de las listas, por ejemplo:
>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
u'Item 2 is carrots.'
Los ndices negativos no estan permitidos. Por ejemplo, la variable de plantilla {{ items.-1 }}
causara un error TemplateSyntaxError.
Las listas de python
Un recordatorio. Las listas de python comienza por el ndice 0.
La bsqueda del punto puede resumirse as: cuando el sistema de plantilla encuentra un punto en
el nombre de la variable, este intentar los siguientes pasos, en este orden:
1. Bsqueda en diccionario (ejemplo, foo[bar])
2. Bsqueda por atributo (ejemplo, foo.bar)
3. Invocacin de mtodo (ejemplo, foo.bar())
4. Bsqueda por ndice (ejemplo, foo[2])
El sistema utiliza el primer tipo de busqueda que funcione. Es un corto circuito logstico. El punto
se puede anidar en mltiples niveles de profundidad. El siguiente ejemplo utiliza {{
person.name.upper }}, que se traduce a una bsqueda en un diccionario y luego una llamada al
mtodo upper():
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name.upper }} is {{ person.age }} years
old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'SALLY is 43 years old.'
Comportamiento de los mtodos
Las invocaciones de mtodos son un poco ms complejas que los dems patrones de bsquedas.
He aqu algunas cosas a tener en cuenta:
Si durante la bsqueda de un mtodo, el mtodo produce una excepcin, la excepcin se
propagar a menos que la excepcin tenga el atributo silent_variable_failure cuyo valor es
True. Si la excepcin tiene el atributo silent_variable_failure, la variable en la plantilla se
proyecta como un string vaco, por ejemplo:
>>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3:
... def first_name(self):
... raise AssertionError, "foo"
>>> p = PersonClass3()
>>> t.render(Context({"person": p}))
Traceback (most recent call last):
...
AssertionError: foo
>>> class SilentAssertionError(AssertionError):
... silent_variable_failure = True
>>> class PersonClass4:
... def first_name(self):
... raise SilentAssertionError
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
u'My name is .'
La invocacin a un mtodo slo funcionar si el mtodo no requiere argumentos. De lo
contrario, el sistema pasar al siguiente tipo de bsqueda (ndices de listas).
Obviamente, algunos mtodos tienen efectos secundarios, y sera lo ms tonto, y
posiblemente incluso un fallo de seguridad, permitir al sistema de plantillas acceder a ellos.
Digamos, por ejemplo, tienes un objeto BankAccount que tiene un mtodo delete(). Si una
plantilla incluye algo como {{ account.delete }}, donde account es un objeto BankAccount,
el objeto sera eliminado cuando la plantilla se analiza.
Para evitar esto, establezca el atributo alters_data de la funcin.
def delete(self):
# Delete the account
delete.alters_data = True
El sistema de plantillas no ejecutar cualquier mtodo marcado de esta forma.
Continuando con el ejemplo anterior, si una plantilla incluye {{ account.delete }} y el
mtdo delete() tiene el atributo alters_data = True, entonces el mtodo delete() no ser
invocado cuando la plantilla se analiza. En su lugar, se producir un error silenciosamente.
Cmo se manejan las variables no vlidas?
Por defecto, si una variable no existe, el sistema de plantilla lo presenta como un string vacio,
fallando silenciosamente. Por ejemplo:
>>> from django.template import Template, Context
>>> t = Template('Your name is {{ name }}.')
>>> t.render(Context())
u'Your name is .'
>>> t.render(Context({'var': 'hello'}))
u'Your name is .'
>>> t.render(Context({'NAME': 'hello'}))
u'Your name is .'
>>> t.render(Context({'Name': 'hello'}))
u'Your name is .'
El sistema falla silenciosamente en lugar de levantar una excepcin, ya que est diseada para
ser resistente a un error humano. En este caso, todas las bsquedas fallarn porque los nombres
de las variables son incorrectos o no coinciden con las maysculas y minsculas. En el mundo real,
es inaceptable para un sitio web que se vuelva inaccesible debido a pequeos errores sintcticos.
Jugando con objetos Context
La mayora de las veces, instanciars los objetos Context pasando un diccionario completo a
Context(). Pero tambin puedes agregar y eliminar elementos del objeto Context una vez ha sido
instanciado utilizando la sintaxis estndar para diccionario en python:
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
Filtros y etiquetas bsicas de las plantillas
Como hemos mencionado anteriormente, el sistema de plantillas viene con etiquetas y filtros
incorporados. En las secciones siguientes se proporciona un resumen de los filtros y etiquetas
ms comunes.
Etiquetas
if / else
La etiqueta {% if %} evala una variable, y si dicha variable es True (es decir, que existe, no
esta vaca, y no es un boolean False), la plantilla mostrar todo entre {% if %} y {% endif %}.
Por ejemplo:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
La etiqueta {% else %} es opcional:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% else %}
<p>Get back to work.</p>
{% endif %}
Truthiness de python
En python y en el sistema de plantillas de Django, los siguientes objetos evalan a False en el
contexto de Boolean:
Una lista vaca ([ ])
Una tupla vaca (( ))
Un diccionario vaco ({ })
Un string vaco ('')
Cero (0)
El objeto especial None
El objeto False (obviamente)
Objetos personalizados que definen su propio comportamiento en el contexto Boolean
(un uso avanzado de python)
Todo lo dems evala a True.
La etiqueta {% if %} acepta operadores and, or, o not para comprobar mltiples variables, o para
negar una determinada variable. Por ejemplo:
{% if athlete_list and coach_list %}
Both athletes and coaches are available.
{% endif %}
{% if not athlete_list %}
There are no athletes.
{% endif %}
{% if athlete_list or coach_list %}
There are some athletes or some coaches.
{% endif %}
{% if not athlete_list or coach_list %}
There are no athletes or there are some coaches.
{% endif %}
{% if athlete_list and not coach_list %}
There are some athletes and absolutely no coaches.
{% endif %}
La etiqueta {% if %} no permite clusulas and y or dentro de la misma etiqueta, ya que el orden
logstico sera ambiguo. Por ejemplo, esto no es vlido:
{% if athlete_list and coach_list or cheerleader_list %}
El uso de los parntesis para controlar el orden de las operaciones no es adimisible. Si ves que
necesitas parntesis, se recomienda realizar la operacin de la plantilla y pasar el resultado como
una variable dedicada a la plantilla. O bien, simplemente puedes anidar la etiqueta {% if %} as:
{% if athlete_list %}
{% if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{% endif %}
{% endif %}
Mltiples usos de los mismos operadores lgicos estn bien, pero no puedes combinar diferentes
operadores. Por ejemplo, lo siguiente es vlido:
{% if athlete_list or coach_list or parent_list or teacher_list %}
Tampoco existe la etiqueta {% elif %}. Puedes lograr lo mismo anidando la etiqueta {% if %}.
{% if athlete_list %}
<p>Here are the athletes: {{ athlete_list }}.</p>
{% else %}
<p>No athletes are available.</p>
{% if coach_list %}
<p>Here are the coaches: {{ coach_list }}.</p>
{% endif %}
{% endif %}
Asegrese de cerrar cada etiqueta {% if %} con un {% endif %}. De lo contrario, Django lanzar
un error TemplateSyntaxError.
for
La etiqueta {% for %} permite iterar sobre cada elemento de una secuencia. Al igual que la
sentencia for de python, la sintaxis es for X in Y, donde Y es la secuencia a recorrer y X es el
nombre de la variable a utilizar en un punto determinado del bucle. Cada vez que se atraviesa el
ciclo, el sistema de plantilla procesar todo entre {% for %} y {% endfor %}.
Por ejemplo, podras utilizar lo siguiente para mostrar una lista de atletas dada la variable
athlete_list:
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
Si agregas reversed a la etiqueta, se recorre la lista en orden inverso:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
Tambin es posible anidar la etiqueta {% for %}:
{% for athlete in athlete_list %}
<h1>{{ athlete.name }}</h1>
<ul>
{% for sport in athlete.sports_played %}
<li>{{ sport }}</li>
{% endfor %}
</ul>
{% endfor %}
Un patrn comn es comprobar el tamao de una lista antes de recorrer sobre este, y mostrar un
texto especial si est vaca:
{% if athlete_list %}
{% for athlete in athlete_list %}
<p>{{ athlete.name }}</p>
{% endfor %}
{% else %}
<p>There are no athletes. Only computer programmers.</p>
{% endif %}
Debido a que este patrn es tan comn, la etiqueta for admite la clusula opcional {% empty %}
que le permite definir que mostrar si la lista est vaca. Este ejemplo es equivalente al anterior:
{% for athlete in athlete_list %}
<p>{{ athlete.name }}</p>
{% empty %}
<p>There are no athletes. Only computer programmers.</p>
{% endfor %}
No hay soporte para detener un ciclo antes que el bucle se complete. Si quieres lograr esto,
cambia el valor de la variable a iterar para que slo recorra por los valores que deseas iterar. Del
mismo modo, no hay soporte para la sentencia continue que le instruye al bucle ir
inmediatamente al prximo ciclo. (Ver seccin Filosofas y limitciones ms adelante en este
captulo para entender el razonamiento en la decisin de este diseo.)
Dentro de cada bucle {% for %}, obtienes acceso a una variable de plantilla llamada forloop. Esta
variable contiene varios atributos que le provee informacin sobre el progreso del bucle:
forloop.counter siempre se establece a un entero representando el nmero de veces que
se ha entrado al bucle. La variable es indexada en base a uno, de modo que en el primer
ciclo, forloop.counter es establecido con valor 1. He aqu un ejemplo:
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}
forloop.counter0 es como forloop.counter, excepto que est basado en ndice cero. Su
valor es establecido al valor 0 la primera vez que recorre el buble.
forloop.revcounter siempre es establecido a un entero representando el nmero de
elementos restante en el bucle. En el primer ciclo del bucle, forloop.revcounter se
establece al nmero total de elementos de la secuencia que estamos recorriendo. En el
ltimo ciclo del bucle, forloop.revcounter es establecido al valor 1.
forloop.revcounter0 es como forloop.revcounter, excepto que est basado en ndice cero.
La primera vez que entra al bucle, forloop.revcounter0 es establecido al nmero total de
elementos de la secuencia menos uno (total - 1). En el ltimo ciclo del bucle, la variable se
establece a 0.
forloop.first es un valor Boolean establecido a True si esta es la primera vez que se recorre
el bucle. Este es conveniente para situaciones especiales:
{% for object in objects %}
{% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
{{ object }}
</li>
{% endfor %}
forloop.last es un valor Boolean establecido a True si este es el ltimo ciclo del bucle. Un
uso comn de este es para poner el caracter pipe (|) entre una lista de enlaces:
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif
%}{% endfor %}
El cdigo de plantilla anterior mostrara algo como lo siguiente:
Link1 | Link2 | Link3 | Link4
Otro uso comn es poner una coma entre una lista de palabras:
Favorite places:
{% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{%
endfor %}
En caso de bucles anidados, forloop.parentloop es una referencia al objeto forloop padre
del bucle actual. He aqu un ejemplo:
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}</td>
<td>City #{{ forloop.counter }}</td>
<td>{{ city }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
La variable forloop esta slo disponbile dentro de los bucles. Despus que el parser de plantilla
haya llegado a {% endfor %}, forloop desaparece.
Contexto y la variable forloop
Dentro del bloque {% for %}, las variables existentes son relocalizados para evitar sobrescribir
la variable forloop. Django expone dicho contexto en el objeto forloop.parentloop.
Generalmente no tienes que preocuparse por esto, pero si provees a la plantilla una variable
llamada forloop (aunque le desaconsejamos su uso), ser renombrado forloop.parentloop
mientras est dentro del bloque {% for %}.
ifequal/ifnotequal
El sistema de plantilla de Django, deliberadamente, no es un lenguaje de programacin completo
y por tanto no te permite ejecutar arbitrariamente cdigo python. (Ms sobre estas ideas en la
seccin Filosofas y limitaciones.) En todo caso, es bastante comn el requisito de comparar dos
valores dentro de la plantilla y mostrar algo si son iguales. Django proporciona la etiqueta {%
ifequal %} para este propsito.
La etiqueta {% ifequal %} compara dos valores y muestra todo entre {% ifequal %} y {%
endifequal %} si los valores son iguales. Este ejemplo compara las variables user y currentuser:
{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% endifequal %}
Los argumentos pueden ser string en el cdigo (hard-coded), con comillas simples o dobles, de
modo que lo siguiente es vlido:
{% ifequal section 'sitenews' %}
<h1>Site News</h1>
{% endifequal %}
{% ifequal section "community" %}
<h1>Community</h1>
{% endifequal %}
Al igual que {% if %}, la etiqueta {% ifequal %} soporta la etiqueta opcional {% else %}.
{% ifequal section 'sitenews' %}
<h1>Site News</h1>
{% else %}
<h1>No News Here</h1>
{% endifequal %}
Solamente variables de plantilla, string, enteros y nmeros decimales son permitidos como
argumentos a {% ifequal %}. Estos son ejemplos vlidos:
{% ifequal variable 1 %}
{% ifequal variable 1.23 %}
{% ifequal variable 'foo' %}
{% ifequal variable "foo" %}
Otros tipos de variables, tales como diccionarios, listas o Booleans, no pueden ser hard-coded en
{% ifequal %}. Estos son ejemplos no vlidos.
{% ifequal variable True %}
{% ifequal variable [1, 2, 3] %}
{% ifequal variable {'key': 'value'} %}
Si necesitas comprobar si algo es True o False, utiliza la etiqueta {% if %} en lugar de {% ifequal
%}.
Comentarios
Justo como en HTML o python, el lenguaje de plantilla de Django permite comentarios. Para
designar un comentario, utiliza la etiqueta {# #}:
{# This is a comment #}
El comentario no ser impreso cuando la plantilla se interpreta. Los comentarios con esta sintaxis
no pueden abarcar mltiples lneas. Esta limitacin mejora el rendimiento al procesar la plantilla.
En la siguiente plantilla, el resultado se ver exactamente igual como en la plantilla (en otras
palabras, la etiqueta de comentario no se procesa como un comentario):
This is a {# this is not
a comment #}
test.
Si quieres usar comentarios de mltiples lneas, utiliza la etiqueta {% comment %} como el
ejemplo:
{% comment %}
This is a
multi-line comment.
{% endcomment %}
Filtros
Como se explic al inicio del captulo, los filtros en la plantilla son formas simples de alterar el valor
de las variables antes de ser mostrado. Los filtros utilizan el carcter pipe (tubera o barra vertical)
de esta manera:
{{ name|lower }}
El ejemplo muestra el valor de la variable {{ name }} despus de ser filtrada a travs del filtro
lower, el cual convierte el texto en minscula. Los filtros tambin pueden ser encadenados es
decir, pueden ser utilizados en conjunto de tal manera que el resultado de un filtro se aplica al
siguiente. He aqu un ejemplo que toma el primer elemento de una lista y la convierte a
maysculas.
{{ my_list|first|upper }}
Algunos filtros pueden tomar argumentos. Un argumento de filtro viene despus de dos puntos y
siempre en comillas dobles. Por ejemplo:
{{ bio|truncatewords:"30" }}
Esto muestra las primeras 30 palabras de la variable bio. La siguiente lista son algunos de los
filtros ms importantes. El Apndice F cubre el resto.
addslashes: agrega backslashes (barra invertida) ante cualquier backslash, comilla simple,
o comilla doble. Esto es til si, por ejemplo, el texto producido es para incluir en un string
de JavaScript.
date: formatea objetos date o datetime de acuerdo a un formato dado en el parmetro. El
string de formato se define en el Apndice F.
{{ pub_date|date:"F j, Y" }}
length: devuelve la longitud del valor. Para una lista, este devuelve el nmero de
elementos. Para un string, devuelve el nmero de caracteres. (Expertos en python, toman
nota de que esto funciona en cualquier objeto python que sabe como determinar su
longitud es decir, cualquier objeto que tenga el mtodo __len__.)
Filosofas y limitaciones
Ahora que tienes una idea del lenguaje de plantilla en Django, debemos sealar algunas
limitaciones intencional, junto con algunas filosofas de por qu funciona de la forma en que
funciona.
Ms que cualquier otro componente de aplicaciones web, la sintaxis de la plantilla es altamente
subjetivo, y las opiniones entre los programadores varan ampliamente. El hecho de que python
por si solo tiene docenas, si no cientos, de lenguajes de plantillas open source (cdigo abierto),
apoyan este punto. Cada uno fue probablemente creado porque los desarrolladores considera los
sistemas de plantillas existentes como inadecuados. (De hecho, se dice que es un rito para
desarrolladores en python escribir su propio lenguaje de plantilla! Si an no lo has hecho,
considralo. Es un ejercicio divertido.)
Con esto en mente, puede que interese saber que Django no le obliga utilizar su propio sistema
de plantillas. Debido que Django intenta ser un framework completo que proporciona todas las
piezas necesarias para que el desarrollador web sea productivo, muchas veces es ms
conveniente utilizar el sistema de plantilla de Django que cualquier otra librera de plantillas en
python, pero en ningn sentido es un requisito estricto. Como se ver en la prxima seccin,
Utilizando plantillas en las vistas, es muy fcil utilizar otro lenguaje de plantilla en Django.
An as, es claro que tenemos una fuerte preferencia por la forma en que el lenguaje de plantillas
de Django funciona. El sistema de plantilla tiene sus fundamentos en cmo se realiza el desarrollo
web en World Online ms la experiencia combinada de los creadores de Django. Estas son
algunas de esas filosofas:
La lgica del negocio debe ser separado de la lgica de presentacin. Los desarrolladores de
Django ven el sistema de plantilla como una herramienta que controla la presentacin y la
lgica de presentacin relacionada a esta y eso es todo. El sistema de plantilla no
debera adherir funcionalidades que van ms all de este objeto bsico.
Por esta razn, es imposible invocar cdigo python directamente dentro de las plantillas de
Django. Toda programacin esta fundamentalmente limitada al mbito de lo que puede
realizar la etiqueta de plantilla. Es posible escribir etiquetas personalizadas que realice
cosas arbitrarias, pero las etiquetas de fbrica en el sistema de plantilla de Django
intencionalmente prohibe la ejecuccin arbitraria de cdigo python.
La sintaxis debe ser disociada de HTML/XML. Aunque el sistema de plantilla de Django se
utiliza principalmente para producir HTML, esta diseada para que sea utilizable con
formatos no HTML, tal como texto plano. Algunos sistemas de plantillas estan basados en
XML, ubicando la lgica de la plantilla entre etiquetas y atributos XML, pero Django evita
deliberadamente esta limitacin. El requisito de generar XML vlido al escribir una plantilla
introduce un mundo de errores humanos que, al analizar los mensajes de error, son de
difcil comprensin. El uso de un motor XML para parsear las plantillas incurren en un nivel
inaceptable de sobrecarga al procesar la plantilla.
Se asume que los diseadores estn familiarizado con cdigo HTML. El sistema de plantilla no
esta diseado para que las plantillas necesariamente se muestren muy bien en los
editores WYSIWYG como Dreamweaver. Es una limitacin muy grave y no permitira que la
sintaxis sea tan amigable como es. Django espera que los autores de plantillas se sientan
cmodos al editar directamente HTML.
Se asume que los diseadores no son programadores en python. Los autores de sistemas de
plantillas reconocen que las plantillas para las pginas web son ms a menudo escrito por
diseadores, no programadores, y por lo tanto no debe asumir el conocimiento en python.
Sin embargo, el sistema tambin intenta acomodar a los equipos pequeos en que las
plantillas son creadas por programadores de python. Este ofrece una forma de extender la
sintaxis del sistema escribiendo cdigo puro en python. (Ms detalles en el captulo
Plantillas avanzadas.)
El objetivo no es inventar un lenguaje de programacin. El objetivo es ofrecer slo la
suficiente funcionalidad programtica, tales como bucles y condicionales, que son
esenciales para realizar decisiones en la presentacin.
Utilizando plantillas en las vistas
Has aprendido los aspectos bsicos del uso del sistema de plantilla; ahora utilicemos ese
conocimientos para crear una vista. Recordemos la vista current_datetime en mysite.views, que
iniciamos en el captulo anterior. He aqu el cdigo:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
Cambiemos esta vista utilizando el sistema de plantilla de Django. En principio, podras pensar
hacer algo como esto:
from django.template import Template, Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = Template("<html><body>It is now {{ current_date
}}.</body></html>")
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
Claro, ah se utiliza el sistema de plantilla, pero no resuelve los problemas que se sealan en la
introduccin de este captulo. Es decir, la plantilla est incrustrada en el cdigo python, por lo que
la verdadera separacin de datos y presentacin an no se logra. Vamos a arreglar eso ubicando
la plantilla en un archivo separado, que esta vista cargar.
Podras considerar guardar la plantilla en algn lugar de tu sistema de archivo y utilizas las
funcionalidades integradas de python para abrir y leer el contenido de la plantilla. He aqu como
podra lucir el cdigo, asumiendo que la plantilla fue almacenada en
/home/djangouser/templates/mytemplate.html:
from django.template import Template, Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
# Simple way of using templates from the filesystem.
# This is BAD because it doesn't account for missing files!
fp = open('/home/djangouser/templates/mytemplate.html')
t = Template(fp.read())
fp.close()
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
Sin embargo, este enfoque no es elegante por varias razones:
No maneja la situacin en que el archivo no se encuentre. Si el archivo mytemplate.html no
existe o no es legible, la invocacin a call() levantara la excepcin IOError.
La localizacin de la plantilla est escrita directamente (hard-coded) en el cdigo. Si fueras
a utilizar esta tcnica para todas las vistas, estaras duplicando la ubicacin de la plantilla.
Sin olvidar que implica mucha escritura!
Incluye una gran cantidad de cdigo repetitivo aburrido. Tienes cosas mejores que hacer
que realizar llamadas a open(), fp.read(), y fp.close() cada vez que cargas una plantilla.
Para resolver estos problemas, vamos a usar las tcnicas template loading y template directories.
Cargando plantilla
Django proporciona una potente y conveniente API para cargar plantillas del sistema de archivos,
con el objetivo de eliminar la redundancia tanto al cargar plantillas como en la plantilla en s
misma. Con el fin de utilizar esta API, primero necesitars indicarle a Django dnde estn
almacenados las plantillas. El lugar para hacer esto es en el archivo de configuraciones el
archivo settings.py que hemos mencionado en el captulo anterior, cuando hablamos sobre
ROOT_URLCONF. Si estas siguiendo los ejercicios, abre el archivo settings.py y localiza la
configuracin TEMPLATE_DIRS. Por defecto, es una tupla vaca, probablemente con algunos
comentarios autogenerados:
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or
"C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
Esta configuracin le indica al mecanismo de la API para cargar plantillas en Django dnde localizar
las plantillas. Elije un directorio en el que deseas almacenar las plantillas y agregalo a
TEMPLATE_DIRS, as:
TEMPLATE_DIRS = (
'/home/django/mysite/templates',
)
Hay algunas cosas a tener en cuenta:
Se puede indicar cualquier directorio que desees, siempre y cuando el directorio y las
plantillas en ellas sean legible por la cuenta de usuario en la que el servidor web se
ejecuta. Si no puedes pensar por un lugar apropiado para ubicar las plantillas, le
recomendamos crear el directorio templates dentro del proyecto es decir, dentro del
directorio mysite que se cre en el captulo Iniciando.
Si TEMPLATE_DIRS contiene un slo directorio, no olvides la coma al final del string! La
razn de esto es porque python requiere una coma dentro de una tupla de un slo
elemento para eliminar la ambigedad con una expresin en parntesis. Se trata de un
error comn en los novatos.
# Mal! Falta la coma al final.
TEMPLATE_DIRS = (
'/home/django/mysite/templates'
)
# Bien. La coma est presente.
TEMPLATE_DIRS = (
'/home/django/mysite/templates',
)
Si ests en Windows, incluye la letra de la unidad y utiliza la barra diagonal (forward slash)
en lugar de la barra diagonal inversa (backslash), como el ejemplo:
TEMPLATE_DIRS = (
'C:/www/django/templates',
)
Lo ms simple es utilizar rutas absolutas es decir, rutas de directorios que comienzan en
la raz del sistema de archivos. Sin embargo, si quieres ser un poco ms flexible y
desacoplado, puedes tomar ventaja del factor que el archivo de configuracin de Django
es simplemente cdigo python y construir dinmicamente el contenido de TEMPLATE_DIRS.
Por ejemplo:
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)
Este ejemplo utiliza la variable mgica __file__ de python, que automaticamente su valor
es establecido al nombre de archivo del mdulo en que el cdigo python reside. Este
obtiene el nombre del directorio que contiene a settings.py (os.path.dirname), luego lo
unifica con templates de forma multi-plataforma (os.path.join), y finalmente se asegura
que se utilice forward slashes en lugar de backslashes (en caso del sistema Windows).
Mientras estamos en el tema de cdigo python dinmico en el archivo de configuraciones,
hay que sealar que es muy importante evitar errores en la configuracin. Si introduces un
error sintctico, o un error en ejecuccin (runtime error), es muy probable que el sitio web
manejado por Django colapse.
Una vez ajustado el TEMPLATE_DIRS, el prximo paso es cambiar el cdigo de la vista para que
utilice las funcionalidades de cargar plantillas de Django en lugar de explicitamente escribir la ruta
al cdigo. Volviendo a nuestra vista current_datetime, vamos a cambiarlo:
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = get_template('current_datetime.html')
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
En este ejemplo, utilizamos la funcin django.template.loader.get_template() en lugar
manualmente cargar la plantilla desde el sistema de archivos. La funcin get_template() toma el
nombre de la plantilla como argumento, determina dnde la plantilla reside en el sistema de
archivos, abre el archivo, y devuelve un objeto Template compilado.
En este ejemplo, nuestra plantilla es current_datetime.html, pero no hay nada especial en la
extensin .html. Puedes asignarle a la plantilla cualquier extensin que haga ms sentido a tu
aplicacin, o puedes prescindir completamente de la extensin.
Para determinar la localizacin de la plantilla en el sistema de archivos, get_template() combina el
directorio de plantilla en TEMPLATE_DIRS con el nombre de la plantilla indicada en get_template().
Por ejemplo, si TEMPLATE_DIRS es establecido a /home/django/mysite/templates, la invocacin a
get_template() buscara la plantilla /home/django/mysite/templates/current_datetime.html.
Si get_template() no puede encontrar la plantilla con el nombre indicado, se levanta una excepcin
TemplateDoesNotExist. Para ver como luce, inicia el servidor de desarrollo en Django ejecutando
python manage.py runserver dentro del directorio del proyecto Django. Entonces, apunta el
navegador hacia la pgina que activa la vista current_datetime (es decir,
http://127.0.0.1:8000/time/). Asumiendo que la configuracin DEBUG est establecida a True y
an no se ha creado la plantilla current_datetime.html, deberas observar una pgina de error de
Django resaltando el error TemplateDoesNotExist.
Figura 4-1: Pgina de error mostrada cuando la plantilla no puede ser localizada.
Esta pgina de error es similar a la que explicamos en el captulo Vistas y URLconfs, con una
pieza adicional de informacin depurada: la seccin Template-loader postmortem. Esta seccin le
dice cual plantilla Django intent cargar, junto con el motivo de cada intento fallido es decir,
File does not exist (El archivo no existe). Esta informacin es valiosa cuando ests tratando
depurar los errores al cargar plantillas.
Continuando, crea el archivo current_datetime.html dentro de tu directorio de plantillas utilizando
el siguiente cdigo:
<html><body>It is now {{ current_date }}.</body></html>
Recarga la pgina en tu navegador web, y deberas ver la pgina completamente procesada.
render_to_response()
Weve shown you how to load a template, fill a Context and return an HttpResponse object with
the result of the rendered template. Weve optimized it to use get_template() instead of
hard-coding templates and template paths. But it still requires a fair amount of typing to do those
things. Because this is such a common idiom, Django provides a shortcut that lets you load a
template, render it and return an HttpResponse all in one line of code.
This shortcut is a function called render_to_response(), which lives in the module
django.shortcuts. Most of the time, youll be using render_to_response() rather than loading
templates and creating Context and HttpResponse objects manually unless your employer
judges your work by total lines of code written, that is.
Heres the ongoing current_datetime example rewritten to use render_to_response():
from django.shortcuts import render_to_response
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date':
now})
What a difference! Lets step through the code changes:
We no longer have to import get_template, Template, Context, or HttpResponse. Instead, we
importdjango.shortcuts.render_to_response. The import datetime remains.
Within the current_datetime function, we still calculate now, but the template loading, context
creation, template rendering, and HttpResponse creation are all taken care of by the
render_to_response() call. Becauserender_to_response() returns an HttpResponse object, we
can simply return that value in the view.
The first argument to render_to_response() is the name of the template to use. The second
argument, if given, should be a dictionary to use in creating a Context for that template. If you
dont provide a second argument,render_to_response() will use an empty dictionary.
The locals() Trick
Consider our latest incarnation of current_datetime:
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date':
now})
Many times, as in this example, youll find yourself calculating some values, storing them in
variables (e.g., now in the preceding code), and sending those variables to the template.
Particularly lazy programmers should note that its slightly redundant to have to give names for
temporary variables and give names for the template variables. Not only is it redundant, but also
its extra typing.
So if youre one of those lazy programmers and you like keeping code particularly concise, you can
take advantage of a built-in Python function called locals(). It returns a dictionary mapping all local
variable names to their values, where local means all variables that have been defined within
the current scope. Thus, the preceding view could be rewritten like so:
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())
Here, instead of manually specifying the context dictionary as before, we pass the value of
locals(), which will include all variables defined at that point in the functions execution. As a
consequence, weve renamed the now variable tocurrent_date, because thats the variable name
that the template expects. In this example, locals() doesnt offer a hugeimprovement, but this
technique can save you some typing if you have several template variables to define or if youre
lazy.
One thing to watch out for when using locals() is that it includes every local variable, which may
comprise more variables than you actually want your template to have access to. In the previous
example, locals() will also include request. Whether this matters to you depends on your
application and your level of perfectionism.
Subdirectories in get_template()
It can get unwieldy to store all of your templates in a single directory. You might like to store
templates in subdirectories of your template directory, and thats fine. In fact, we recommend
doing so; some more advanced Django features (such as the generic views system, which we
cover in Chapter 11) expect this template layout as a default convention.
Storing templates in subdirectories of your template directory is easy. In your calls to
get_template(), just include the subdirectory name and a slash before the template name, like so:
t = get_template('dateapp/current_datetime.html')
Because render_to_response() is a small wrapper around get_template(), you can do the same
thing with the first argument to render_to_response(), like this:
return render_to_response('dateapp/current_datetime.html',
{'current_date': now})
Theres no limit to the depth of your subdirectory tree. Feel free to use as many subdirectories as
you like.
Note
Windows users, be sure to use forward slashes rather than backslashes. get_template() assumes
a Unix-style file name designation.
The include Template Tag
Now that weve covered the template-loading mechanism, we can introduce a built-in template tag
that takes advantage of it: {% include %}. This tag allows you to include the contents of another
template. The argument to the tag should be the name of the template to include, and the
template name can be either a variable or a hard-coded (quoted) string, in either single or double
quotes. Anytime you have the same code in multiple templates, consider using an {% include %}
to remove the duplication.
These two examples include the contents of the template nav.html. The examples are equivalent
and illustrate that either single or double quotes are allowed:
{% include 'nav.html' %}
{% include "nav.html" %}
This example includes the contents of the template includes/nav.html:
{% include 'includes/nav.html' %}
This example includes the contents of the template whose name is contained in the variable
template_name:
{% include template_name %}
As in get_template(), the file name of the template is determined by adding the template directory
fromTEMPLATE_DIRS to the requested template name.
Included templates are evaluated with the context of the template thats including them. For
example, consider these two templates:
# mypage.html
<html>
<body>
{% include "includes/nav.html" %}
<h1>{{ title }}</h1>
</body>
</html>
# includes/nav.html
<div id="nav">
You are in: {{ current_section }}
</div>
If you render mypage.html with a context containing current_section, then the variable will be
available in the included template, as you would expect.
If, in an {% include %} tag, a template with the given name isnt found, Django will do one of two
things:
If DEBUG is set to True, youll see the TemplateDoesNotExist exception on a Django error
page.
If DEBUG is set to False, the tag will fail silently, displaying nothing in the place of the tag.
Template Inheritance
Our template examples so far have been tiny HTML snippets, but in the real world, youll be using
Djangos template system to create entire HTML pages. This leads to a common Web development
problem: across a Web site, how does one reduce the duplication and redundancy of common
page areas, such as sitewide navigation?
A classic way of solving this problem is to use server-side includes, directives you can embed within
your HTML pages to include one Web page inside another. Indeed, Django supports that
approach, with the {% include %} template tag just described. But the preferred way of solving
this problem with Django is to use a more elegant strategy called template inheritance.
In essence, template inheritance lets you build a base skeleton template that contains all the
common parts of your site and defines blocks that child templates can override.
Lets see an example of this by creating a more complete template for our current_datetime view,
by editing thecurrent_datetime.html file:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>The current time</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
<p>It is now {{ current_date }}.</p>
<hr>
<p>Thanks for visiting my site.</p>
</body>
</html>
That looks just fine, but what happens when we want to create a template for another view
say, the hours_ahead view from Chapter 3? If we want again to make a nice, valid, full HTML
template, wed create something like:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>Future time</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
<hr>
<p>Thanks for visiting my site.</p>
</body>
</html>
Clearly, weve just duplicated a lot of HTML. Imagine if we had a more typical site, including a
navigation bar, a few style sheets, perhaps some JavaScript wed end up putting all sorts of
redundant HTML into each template.
The server-side include solution to this problem is to factor out the common bits in both templates
and save them in separate template snippets, which are then included in each template. Perhaps
youd store the top bit of the template in a file called header.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
And perhaps youd store the bottom bit in a file called footer.html:
<hr>
<p>Thanks for visiting my site.</p>
</body>
</html>
With an include-based strategy, headers and footers are easy. Its the middle ground thats
messy. In this example, both pages feature a title <h1>My helpful timestamp site</h1> but
that title cant fit into header.html because the<title> on both pages is different. If we included the
<h1> in the header, wed have to include the <title>, which wouldnt allow us to customize it per
page. See where this is going?
Djangos template inheritance system solves these problems. You can think of it as an inside-out
version of server-side includes. Instead of defining the snippets that are common, you define the
snippets that are different.
The first step is to define a base template a skeleton of your page that child templates will later
fill in. Heres a base template for our ongoing example:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
This template, which well call base.html, defines a simple HTML skeleton document that well use
for all the pages on the site. Its the job of child templates to override, or add to, or leave alone
the contents of the blocks. (If youre following along, save this file to your template directory as
base.html.)
Were using a template tag here that you havent seen before: the {% block %} tag. All the {%
block %} tags do is tell the template engine that a child template may override those portions of
the template.
Now that we have this base template, we can modify our existing current_datetime.html template
to use it:
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}
While were at it, lets create a template for the hours_ahead view from Chapter 3. (If youre
following along with code, well leave it up to you to change hours_ahead to use the template
system instead of hard-coded HTML.) Heres what that could look like:
{% extends "base.html" %}
{% block title %}Future time{% endblock %}
{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}
Isnt this beautiful? Each template contains only the code thats unique to that template. No
redundancy needed. If you need to make a site-wide design change, just make the change to
base.html, and all of the other templates will immediately reflect the change.
Heres how it works. When you load the template current_datetime.html, the template engine
sees the {% extends %}tag, noting that this template is a child template. The engine immediately
loads the parent template in this case,base.html.
At that point, the template engine notices the three {% block %} tags in base.html and replaces
those blocks with the contents of the child template. So, the title weve defined in {% block title
%} will be used, as will the{% block content %}.
Note that since the child template doesnt define the footer block, the template system uses the
value from the parent template instead. Content within a {% block %} tag in a parent template is
always used as a fallback.
Inheritance doesnt affect the template context. In other words, any template in the inheritance
tree will have access to every one of your template variables from the context.
You can use as many levels of inheritance as needed. One common way of using inheritance is the
following three-level approach:
1. Create a base.html template that holds the main look and feel of your site. This is the stuff
that rarely, if ever, changes.
2. Create a base_SECTION.html template for each section of your site (e.g., base_photos.html
andbase_forum.html). These templates extend base.html and include section-specific
styles/design.
3. Create individual templates for each type of page, such as a forum page or a photo gallery.
These templates extend the appropriate section template.
This approach maximizes code reuse and makes it easy to add items to shared areas, such as
section-wide navigation.
Here are some guidelines for working with template inheritance:
If you use {% extends %} in a template, it must be the first template tag in that template.
Otherwise, template inheritance wont work.
Generally, the more {% block %} tags in your base templates, the better. Remember, child
templates dont have to define all parent blocks, so you can fill in reasonable defaults in a
number of blocks, and then define only the ones you need in the child templates. Its better to
have more hooks than fewer hooks.
If you find yourself duplicating code in a number of templates, it probably means you should
move that code to a{% block %} in a parent template.
If you need to get the content of the block from the parent template, use {{ block.super }},
which is a magic variable providing the rendered text of the parent template. This is useful if
you want to add to the contents of a parent block instead of completely overriding it.
You may not define multiple {% block %} tags with the same name in the same template. This
limitation exists because a block tag works in both directions. That is, a block tag doesnt
just provide a hole to fill, it also defines the content that fills the hole in the parent. If there
were two similarly named {% block %} tags in a template, that templates parent wouldnt
know which one of the blocks content to use.
The template name you pass to {% extends %} is loaded using the same method that
get_template() uses. That is, the template name is appended to your TEMPLATE_DIRS setting.
In most cases, the argument to {% extends %} will be a string, but it can also be a variable, if
you dont know the name of the parent template until runtime. This lets you do some cool,
dynamic stuff.
No prestar atencin a este bloque, es de uso personal mientras se trabaja el capitulo
H1 The Django Book
H2 Chapter 4: Templates
H3 Template System Basics
H3 Using the Template System
H4 Creating Template Objects
H4 Rendering a Template
H4 Multiple Contexts, Same Template
H4 Context Variable Lookup
H5 Method Call Behavior
H5 How Invalid Variables Are Handled
H4 Playing with Context Objects
H3 Basic Template Tags and Filters
H4 Tags
H5 if/else1
H5 for2
H5 ifequal/ifnotequal
H5 Comments
H4 Filters
H3 Philosophies and Limitations
H3 Using Templates in Views
H3 Template Loading
H4 render_to_response()9
H4 The locals() Trick
H4 Subdirectories in get_template()
H4 The include Template Tag
H3 Template Inheritance3
H3 Whats next?3
H4 About this comment system
#code
iterator = document.createNodeIterator(document.body, NodeFilter.SHOW_ELEMENT,
function(node){
if(/h\d/i.test(node.nodeName)) return NodeFilter.FILTER_ACCEPT;
return NodeFilter.FILTER_SKIP;
}, true);
while(iter = iterator.nextNode()){
for(var times = iter.nodeName.match(/\d/)[0] -1, space = ""; times > 0; times--)
space += "\t";
console.log(space, iter.nodeName, iter.textContent);
}
Captulo 5: Modelos
En el captulo 3, cubrimos los conceptos fundamentales de la creacin de sitios Web dinmicos con
Django: la creacin de vistas y URLconfs. Como explicamos, una vista es responsable de
implementar alguna lgica arbitraria, y despus devolver una respuesta. En uno de los ejemplos,
nuestra lgica arbitraria fue calcular la fecha y hora actuales.
En aplicaciones Web modernas, la lgica arbitraria a menudo involucra interaccin con una base
de datos. Detrs de escena, un sitio Web impulsado por una base de datos se conecta a un servidor
de base de datos, recupera algunos datos de esta, y muestra estos datos en una pgina Web. El
sitio tambin podra proporcionar funciones a los visitantes del sitio para poblar la base de datos
ellos mismos.
Muchos sitios Web complejos proporcionan una combinacin de los dos. Amazon.com, por ejemplo,
es un buen caso de un sitio impulsado por una base de datos. Cada pgina de producto es
bsicamente es una consulta en la base de datos de productos de Amazon formateada como
HTML, y cuando envas una resea, es insertada en la base de datos de las reseas.
Django es adecuado para crear sitios Web impulsados por bases de datos, ya que incluye
herramientas para realizar consultas a la base de datos de una manera fcil pero poderosa. Este
captulo explica esta funcionalidad: La capa de base de datos de Django.
Nota: Aunque no es estrictamente necesario conocer teora bsica de bases de datos relacionales
y SQL para usar la capa de base de datos de Django, es muy recomendble. Una introduccin a
esos conceptos est fuera del alcance de este libro, pero contina leyendo si eres nuevo en bases
de datos. Probablemente sers capz de seguir y entender los conceptos en funcin del contexto.
La manera Tonta de hacer consultas a la base de datos en las vistas
As como en el Captulo 3 vimos la manera tonta de generar una salida en una vista
(hardcodeando el texto directamente dentro de la vista), hay una manera tonta de recuperar
datos desde una base de datos en una vista. Es simple: solo usa una librera existente en Python
para ejecutar una consulta SQL y haz algo con los resultados.
En este ejemplo de vista, usamos la librera MySQLdb (disponible en
http://www.djangoproject.com/r/python-mysql/) para conectarse a una base de datos MySQL,
recuperar algunos registros, y alimentar con ellos un template para mostrar una pgina Web:
from django.shortcuts import render_to_response
import MySQLdb
def book_list(request):
db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost')
cursor = db.cursor()
cursor.execute('SELECT name FROM books ORDER BY name')
names = [row[0] for row in cursor.fetchall()]
db.close()
return render_to_response('book_list.html', {'names': names})
Esta manera de abordar el problema funciona, pero hay algunos problemas que saltan a la vista
inmediatamente:
Estamos escribiendo directamente en el cdigo los parmetros de la coneccion a la base de
datos. Lo ideal, es poner estos parmetros en el archivo de configuracin de nuestro
proyecto Django.
Were having to write a fair bit of boilerplate code: creating a connection, creating a cursor,
executing a statement, and closing the connection. Ideally, all wed have to do is specify which
results we wanted.
It ties us to MySQL. If, down the road, we switch from MySQL to PostgreSQL, well have to use
a different database adapter (e.g., psycopg rather than MySQLdb), alter the connection
parameters, and depending on the nature of the SQL statement possibly rewrite the SQL.
Ideally, the database server were using would be abstracted, so that a database server
change could be made in a single place. (This feature is particularly relevant if youre building
an open-source Django application that you want to be used by as many people as possible.)
As you might expect, Djangos database layer aims to solve these problems. Heres a sneak
preview of how the previous view can be rewritten using Djangos database API:
django.shortcuts import render_to_response
from mysite.books.models import Book
def book_list(request):
books = Book.objects.order_by('name')
return render_to_response('book_list.html', {'books': books})
Captulo 6: El sitio admin de Django
Para cierta clase de sitios web, una interfaz de admin (o interfaz de administracin) es parte
esencial de la infraestructura. Esta es una interfaz web, limitada a los administradores del
sitio, que permite aadir, editar y borrar contenido del sitio. Algunos ejemplos comunes: la
interfaz que usas cuando creas una entrada en un blog, el sitio que los administradores usan
para moderar los comentarios, las herramientas que usan tus clientes para actualizar su sitio
web que tu les construiste.
Hay un problema con las interfaces de administracin: Es aburrido construirlas. El desarrollo
web es divertido cuando estas desarrollando una funcionalidad que se enfrenta al pblico,
pero construir interfaces de administracin es siempre lo mismo. Tienes que autentificar
usuarios, desplegar y manejar los formularios, validar la entrada, etc. Es aburrido y repetitivo.
Entonces, Cual es el enfoque de django para este aburrimiento y tareas repetitivas? El
enfoque es que django te provee de todo en tan solo un par de lineas de cdigo, no
menos. Con django, construir interfaces de administracin es un problema resuelto.
Este captulo es acerca de la interfaz de administracin automtica de django. Esta
caracterstica, funciona de la siguiente manera: Lee la metadata en tu modelo para proveer
una lista-para-produccin y poderosa interfaz que los administradores de sitios pueden
empezar a usar inmediatamente. Aqu, vamos a hablar de como activar, usar y personalizar
esta caracterstica.
Nota que nosotros recomendamos que leas este captulo inclusive si no tienes intensiones de
usar el sitio de administracin de django, por que aqu introducimos algunos conceptos que
aplica para todo django, a pesar del no uso del sitio de administracin.