You are on page 1of 62

Introduccin a Django:

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 print print print print "Content-Type: text/html\n" "<html><head><title>Books</title></head>" "<body>" "<h1>Books</h1>" "<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 4. 5.
2 Refactoriza el cdigo entonces la aplicacin 1 y 2 pueden compartir el cdigo 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 . (dot) \d [A-Z] [a-z] [A-Za-z] +

Coincide Cualquier carcter. Un solo dgito decimal. Cualquier cracter entre A y Z (uppercase) Cualquier cracter entre a y z (lowercase) 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). Entre 1 y 3 (inclusive) de la expresin previa (ejemplo: \d{1,3} coincide uno, dos o tres dgitos)

{1,3}

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 ifequal ifequal ifequal

variable variable variable variable

1 %} 1.23 %} 'foo' %} "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 sectionwide 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.

You might also like