django book español - google drive

60
Introducción 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 pequeños requisitos. Experiencia en programación: conceptos básicos como variables, estructuras de control (ejemplo: if, for, while), estructura de datos (listas, tuplas, diccionarios), clases y objetos, y por supuesto programación orientada a objetos. Experiencia programando en python: Django es una colección de librerías escritas en python. Entonces para desarrollar sitios usando django tienes que escribir código 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 líneas de código en otros lenguajes con python puedes hacerlo de una manera simple y en pocas líneas. 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 generación de web frameworks pero ¿que es lo que este término precisamente significa? Para contestar esta pregunta, vamos a considerar el diseño de una aplicación web escrita en python sin un framework. A través de este tutorial, vamos a tomar este enfoque de trabajar sin frameworks o atajos y después ver como lo haríamos con atajos. Una de las maneras más simples y directas de construir una aplicación web escrita en python sin utilizar ningún framework es usar CGI (Common Gateway Interface) estándar, que fue una técnica muy popular a finales de los 90's para desarrollar páginas web dinámicas y no simplemente HTML estático. Aquí una explicación 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 extensión ".cgi" y visita la pagina desde tu explorador web favorito. Y eso es todo. Aquí un ejemplo de python CGI (suponga que funciona): #!/usr/bin/env python import MySQLdb print "Content‐Type: text/html \n " print "<html><head><title>Books</title></head>" print "<body>" print "<h1>Books</h1>" print "<ul>"

Upload: jose-g-yzarra

Post on 29-Oct-2015

78 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Django Book Español - Google Drive

Introducción a Django:

Este tutorial está basado en el "Django book". Cualquier duda, comentario o sugerenciaaquí. Antes que empieces a leer este grandioso tutorial, voy a necesitar que cumplas conunos pequeños requisitos.

Experiencia en programación: conceptos básicos como variables, estructuras de control(ejemplo: if, for, while), estructura de datos (listas, tuplas, diccionarios), clases y objetos, y porsupuesto programación orientada a objetos.

Experiencia programando en python: Django es una colección de librerías escritas en python.Entonces para desarrollar sitios usando django tienes que escribir código en python. En caso deque no sepas programar en python estas de suerte por que aprender a programar en python esun placer, cosas que te pueden llevar varias líneas de código en otros lenguajes con pythonpuedes hacerlo de una manera simple y en pocas líneas. Si buscas libros para aprender pythonte recomiendo "python para todos" o "Dive into python".

¿Qué es un web framework?Django es un prominente miembro de una nueva generación de web frameworks ­ pero¿que es lo que este término precisamente significa?

Para contestar esta pregunta, vamos a considerar el diseño de una aplicación web escritaen python sin un framework. A través de este tutorial, vamos a tomar este enfoque detrabajar sin frameworks o atajos y después ver como lo haríamos con atajos.

Una de las maneras más simples y directas de construir una aplicación web escrita enpython sin utilizar ningún framework es usar CGI (Common Gateway Interface) estándar,que fue una técnica muy popular a finales de los 90's para desarrollar páginas webdinámicas y no simplemente HTML estático.

Aquí una explicación de alto nivel de como funciona: solo crea un script en python queimprima HTML, luego salva el script en un servidor web con la extensión ".cgi" y visita lapagina desde tu explorador web favorito. Y eso es todo.

Aquí un ejemplo de python CGI (suponga que funciona):

#!/usr/bin/env python

import MySQLdb

print "Content‐Type: text/html\n"

print "<html><head><title>Books</title></head>"

print "<body>"

print "<h1>Books</h1>"

print "<ul>"

Page 2: Django Book Español - Google Drive

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 unalínea en blanco después imprimir algo de HTML, hace una conexión a una base de datos,obtiene algunos registros y los imprime formateado con HTML, termina de imprimir el HTMLy cierra la conexión.

Con una página como esta, el escribir todo desde 0 no es necesariamente malo. Este códigoes simple de comprender ­ inclusive un programador novato puede leer estas 16 líneas decódigo de python y entender todo, de principio a fin. Como pueden observar no hay muchoque aprender y no hay otro código más que leer. Además es simple de llevar a producción:solo salva el código en un archivo que tenga la extensión .cgi, sube el archivo al servidorweb y visita la página desde tu explorador.

Pero a pesar de su simplicidad, este enfoque tiene números problemas y fastidios. Solopregúntate a ti mismo las siguientes preguntas:

¿Qué pasa cuando múltiples partes de la aplicación necesitan estar conectadas a la base dedatos? Seguramente ese código para conectar a la base de datos no necesitaría ser duplicado encada script CGI que hagamos. Lo ideal sería refactorizar el código en una función compartidapara conectarnos a la base de datos.

¿Debe el desarrollador realmente preocuparse acerca de imprimir la linea Content‐Type yrecordar cerrar la conexión a la base de datos? Este tipo de asuntos reduce la productividad deun programador e introduce oportunidades para errores.

¿Qué pasa cuando el código es reutilizado en múltiples ambientes, cada uno con una base dedatos y contraseñas separadas? En este punto, algunas configuraciones de ambientesespecíficos se vuelven esenciales.

¿Qué pasa cuando un diseñador web sin experiencia codificando en python desea rediseñar lapágina? Un carácter mal puesto y la aplicación entera puede fallar. Idealmente, la lógica de lapágina ­ el obtener registros de libros de la base de datos ­ debería de estar separada del HTMLque despliega la página, entonces el diseñador puede editar el HTML sin afectar la lógica de laaplicación.

Estos problemas son precisamente los problemas que un web framework trata de resolver.Un web framework provee de una infraestructura para programar tus aplicaciones, ademásde que te puedes concentrar en escribir código limpio y mantenible sin tener que reinventarla rueda. En pocas palabras eso es lo que Django hace.

Page 3: Django Book Español - Google Drive

El diseño del patrón MVCVamos a ver un rápido ejemplo que demuestra la diferencia entre el anterior y un enfoquecon un web framework. Aquí esta como más o menos se escribiría el anterior código de CGIusando 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>

Page 4: Django Book Español - Google Drive

Otra vez, no te preocupes de la sintaxis; solo trata de entender el diseño general. Laprincipal cosa a notar aquí es la separación de asuntos:

El archivo models.py contiene una descripción de las tablas de la base de datos, representadaspor una clase. Esta clase es llamada un modelo. Usándola puedes crear, obtener, actualizar yborrar registros en tu base de datos usando simple código python en vez de escribir unasentencia SQL que puede ser repetitiva.

El archivo views.py contiene la lógica del negocio para la página. La función latest_book esllamada una vista.

El archivo urls.py especifica que vista debe ser llamada dado un patrón de URL. En este caso, laURL /latest/ será manejada por la función latest_books(). En otras palabras, si tu dominio esexample.com, cualquiera que visite http://example.com/latest/ va a llamar a la funciónlatest_books().

El archivo latest_books.html es un template (o plantilla) que describe el diseño de la página,usando un lenguaje de template con básicas sentencias lógicas ­ ejemplo % for book inbook_list %.

Si tomamos todas las piezas y las juntamos aproximadamente siguen un patrón llamadoMVC (Model­View­Controller).

La ventaja clave de tal enfoque es que los componentes son loosely coupled. Cada pieza deuna aplicación web hecha con Django tiene un solo propósito clave y puede ser cambiadoindependientemente sin afectar las otras piezas. Por ejemplo, un desarrollador puedecambiar la URL de cierta parte de la aplicación sin afectar las otras piezas de la aplicación.Un diseñador puede cambiar el HTML de un template (o plantilla) sin tener que tocar elcódigo de python. Un administrador de base de datos puede renombrar una tabla de la basede datos y especificar el cambio en un solo lugar, en vez de tener que buscar y reemplazara través de una docena de archivos.

La historia de DjangoAntes de empezar a bucear entre más código, debemos tomar un momento para explicar lahistoria de Django. Como dijimos anteriormente te vamos a mostrar como hacer las cosassin usar atajos, además vas a entender mejor los atajos. Similarmente, es útil entender porqué fue creado Django, por qué el conocimiento de la historia te pondrá en un contexto deporque Django trabaja en la manera en que lo hace.

Si has estado construyendo aplicaciones web por un tiempo, probablemente estasfamiliarizado con los problemas del ejemplo CGI que presentamos anteriormente. La rutaclásica del desarrollo web va más o menos así:

1. Escribe una aplicación web desde 0

2. Escribe otra aplicación web desde 0

3. Date cuenta que la aplicación del paso 1 comparte mucho en común con la aplicación del paso 2

4. Refactoriza el código entonces la aplicación 1 y 2 pueden compartir el código

5. Repite los pasos del 2 al 4 varias veces

6. Date cuenta que has inventado un framework

Page 5: Django Book Español - Google Drive

Esto es precisamente como Django fue creado.

Django creció originalmente de aplicaciones del mundo real escritas por un equipodesarrollo web en Lawrence, Kansas, USA. Django nació en el otoño de 2003, cuando losprogramadores web del periódico "Lawrence Journal­World", Adrian Holovaty y SimonWillison, empezaron usando python para construir aplicaciones.

El equipo "World Online", responsable de la producción y mantenimiento de varios sitios denoticias locales, prosperado en un ambiente de desarrollo dictado por los tiempos limitesdel periodismo. Para los sitios ­ incluyendo LJWorld.com, Lawrence.com y KUsports.com ­periodistas (y administradores) demandaban que fueran añadidas características yaplicaciones enteras fueran construidas en una intensamente rápida agenda, comúnmentecon solo días u horas para desarrollarlo. De este modo, Simon y Adrian habían desarrolladoun web framework que les ahorraba tiempo ­ esa fue la única manera en que ellos pudieronconstruir aplicaciones mantenibles bajo los estrictos tiempos de entrega.

En el verano del 2005, después de habiendo desarrollado este framework hasta un puntodonde eficientemente impulsaba la mayoría de los sitios "World Online", el equipo, el cualahora incluía a Jacob Kaplan­Moss, decidieron liberar el framework como software decódigo abierto. Lo liberaron en Julio de 2005 y lo llamaron Django, en honor al guitarristade jazz Django Reinhardt.

Ahora, varios años después, Django esta bien establecido como un proyecto de softwarelibre con más de diez mil usuarios y colaboradores esparcidos a través de todo el mundo.Dos de los desarrolladores originales de Word Online ("Los benevolentes dictadores de lavida", Adrian y Jacob) aún proveen una guía central para el crecimiento del framework,pero es mucho más 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 variascaracterísticas (como un sitio de administración) que son particularmente adecuados parasitios de "contenido" ­ sitios como amazon.com, craigslist.org y washingtonpost.com queofrecen datos de una manera dinámica. ­ A pesar de que Django es particularmente buenopara desarrollar ese tipo de sitios, que no lo excluye de ser una herramienta efectiva paraconstruir cualquier tipo de sitio web dinámico.

El segundo punto, muestra como los orígenes de Django han formado la cultura de sucomunidad de software libre. Porque Django fue extraído desde el código del mundo real,en vez de empezar como un ejercicio académico o producto comercial, esta sumamenteenfocado en resolver problemas de desarrollo web que los mismos desarrolladores deDjango se han enfrentado ­ y continúan enfrentando. Como resultado, el mismo Django esactivamente mejorado en una base casi diaria.

IniciandoDjango es "solo" código en python y como python corre donde sea ­ incluyendo celulares.

Page 6: Django Book Español - Google Drive

Pero este capítulo solo cubre escenarios comunes para instalaciones de Django. Vamos aasumir que estas instalándolo en un escritorio/laptop o servidor.

Después (varios capítulos más adelante) veremos como llevar a producción un sitio hechocon Django.

Instalando pythonEn si mismo Django esta escrito completamente en python, entonces el primer paso eninstalar el framework es estar seguro que python esta instalado.

Versiones de pythonEl núcleo del framework Django funciona con cualquier versión de python desde la 2.3 hastala 2.7, dependiendo de la versión del framework las versiones más recientes están dejandode dar soporte a las versiones más antiguas de python. Por eso te recomendamos usar depython 2.5 en adelante.

Si no estas seguro cual versión de python instalar y tienes la libertad de decidir que versióninstalar, entonces te recomendamos instalar la ultima versión de la serie 2.x. A pesar deque Django trabaja igual con cualquier versión de python, las últimas versiones de pythontienen mejoras de rendimiento y características adicionales del lenguaje que tal vez te gusteusar en tus aplicaciones. Además existen add­ons (o extensiones) de terceros para Djangopodrían requerir versiones más nuevas que las versiones 2.3 o 2.4

Django y python 3.xComo saben, python esta en un proceso de transición donde python 3.x intenta desplazarlas versiones 2.x, como ya saben cada versión de python que cambia en su primer dígitotiene cambios importantes y además no es compatible con versiones anteriores, por lo quemuchas aplicaciones se tienen que reescribir y eso incluye a Django.

Actualmente Django no corre completamente en python 3.x, afortunadamente esto se haestado planeando y desarrollando por años. Así que esperamos que muy pronto Django sepueda correr completamente en versiones de python 3.x

InstalaciónSi estas corriendo Linux o Mac OS X, probablemente ya tienes python instalado. Soloescribe python en tu consola (terminal o línea de comandos) favorita. Si vez algo parecido aesto, 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)] onwin32Type "help", "copyright", "credits" or "license" for more information.

Page 7: Django Book Español - Google Drive

>>>

Si eres un usuario del sistema operativo Windows, lo más probable es que no tengasinstalado python.De cualquier forma, si necesitas descargar python puedes hacerlo desde aquíhttp://www.python.org/download/. Las instrucciones son rápidas y fáciles de seguir.Si estas en Windows, te recomiendo bajarte el .exe o .msi ya que compilarlo puede ser algocomplicado (por lo menos en Windows). En cambio, si te encuentras en Linux y tienes unadministrador de paquetes te recomiendo usarlo, ya que regularmente los módulos parapython también puedes instalarlo desde tu administrador de paquetes. Además estospaquetes son elegidos para que trabajen de una manera óptima con tu distribución Linuxtambién con el tiempo obtienes actualizaciones para estos paquetes. Pero si no cuentas conun administrador de paquetes (como apt­get, yum, pacman, …) siempre puedes descargateel código fuente del interprete, compilarlo e instalarlo.

Instalando DjangoDjango tiene típicamente 2 versiones disponibles: la última versión oficial lanzada y laversión experimental llamada "trunk". La versión que decidas instalar depende en tusprioridades. ¿Quieres una versión estable y probada de Django o quieres una versión quetenga las últimas características y probablemente puedas contribuir al mismo frameworkDjango, a costo de la estabilidad?

Nosotros te recomendamos que te pegues a las versiones oficiales (o estables), perotambién es importante saber que la versión "trunk" (o versión en desarrollo) existe.

Instalando la versión oficialLa última versión en el momento que escribo este tutorial, es la versión 1.3. Para descargarla última versión puedes visitar https://www.djangoproject.com/download/. Para losusuarios Linux que tengan administrador de paquetes pueden instalar Django desde suadministrador de paquetes, por lo regular la versión de Django que instala es una versiónestable. Si no tienes acceso a un administrador de paquetes, puedes descargar e instalarDjango manualmente. Para hacer eso visiten la pagina anterior y bajen la última versión,después corran estos comandos.

tar xzvf Django‐<versión>.tar.gz #Suponiendo que estan en el directorio donde lodescargaroncd Django‐*sudo python setup.py install

Y listo a disfrutar Django.

Probando DjangoPara saber que efectivamente instalamos Django, abrimos el intérprete dinámico de pythony escribimos lo siguiente:

Page 8: Django Book Español - Google Drive

import djangodjango.VERSION

Ajustando las bases de datosPara trabajar con Django no es necesario tener una base de datos, pero Django tienemuchas funciones que requieren tener una base de datos y seguramente también teinteresará guardar, obtener, actualizar y borrar datos. Así que por eso es tan necesaria unabase 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 algún sistema viejo y tienes la libertad de escoger una base de datos terecomendamos PostgreSQL, que logra tener un buen balance entre costo, características,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 más allá

del alcance de este tutorial, pero afortunadamente estos 4 motores que soporta Django tienenmucha documentación, una gran comunidad en cada una de estas y la mayoría de estas sonfáciles de instalar.

Segundo, vas a necesitar instalar una librería de python que te permita conectarte a tu base dedatos.

Si solo estas jugando o probando Django y no quieres instalar una base de datos terecomendamos usar SQLite. SQLite es el único motor de base de datos que soporta Djangoque no requiere de ninguna instalación, claro eso si estas usando una versión de python 2.5en adelante.

En Windows, obtener una librería para trabajar con una base de datos puede ser frustante,afortunadamente existe una lista de librerías para python compiladas en binarios (.exe) quepuedes conseguir aquí http://www.lfd.uci.edu/~gohlke/pythonlibs/.

Librerías 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

Page 9: Django Book Español - Google Drive

Empezando un proyectoUna vez instalado python, Django y opcionalmente la librería para conectarnos a la base dedatos, puedes dar el primer paso en desarrollar una aplicación en Django que es crear unproyecto

Un proyecto es una colección de ajustes para una instancia de Django, incluyendo:configuración de la base de datos, opciones específicas de Django y la aplicación.

NOTA: Para fines prácticos, no pongas tu código de python en el document root.

Lo primero que vamos hacer es crear un directorio (o carpeta) y correr el siguientecomando:

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 yademás debe de tener permisos de ejecución esto en caso que hayas instalado Django demanera manual. Si lo instalaste desde un administrador de paquetes probablemente elcomando no se llame django­admin.py si no django­admin . Si estas usando Windows muyprobablemente tengas que añadir python al path y luego ejecutar lo siguiente pythonC:\ruta\a\django\django‐admin.py mysite . De cualquier manera te recomendamos queinstales Eclipse + PyDev para que sea más fácil trabajar en tu proyecto.

Una vez que comenzamos con nuestro proyecto tenemos una estructura más 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 tratadocomo un paquete. Es un archivo vacío y generalmente no vamos añadir nada en el.

manage.py: es una utilidad de la línea de comando, con este archivo vamos a interacturar con elproyecto de varias maneras. Intenta con python manage.py help para darte una idea de lo quepuedes hacer. Nunca, pero nunca debes de editar este archivo.

settings.py: ajustes/configuraciones para el proyecto. Échale un vistazo a los diferentes tiposde configuraciones disponibles y a sus valores por defecto.

urls.py: las URLs del proyecto están en este archivo. Básicamente esto es una "tabla decontenidos" para tu proyecto. Por el momento esta vacío.

A pesar de su tamaño, estos archivos constituyen una aplicación completamente funcional.

Page 10: Django Book Español - Google Drive

Corriendo el servidor de desarrolloLa mayoría del tiempo vamos a correr el servidor de desarrollo para ver como va quedandonuestro proyecto.

El servidor de desarrollo de Django (también llamado "runserver" en honor al comando quelo lanza) es un servidor web integrado y ligero que puedes usar para desarrollar tu sitio.Esta incluido en la instalación de Django entonces puedes desarrollar rápidamente tu sitio,sin estar teniendo que lidiar con la configuración de un servidor web de producción (ejemploApache) hasta que este listo para la producción. El servidor de desarrollo vigila tu código yautomáticamente lo recarga, haciendo fácil para tu cambiar el código sin la necesidad dereiniciar nada.

Para iniciar el servidor, muévete al directorio de tu proyecto (mysite) y ejecuta el siguientecomando:

python manage.py runserver

Después deberías 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 detu propia computadora. Ahora que esta corriendo, visita http://127.0.0.1:8000/ con tunavegador web favorito. Entonces vas a ver "Welcome to Django" en una pagina de tonoazul.

También pueden cambiar el puerto por donde escucha el servidor web de la siguientemanera:

Page 11: Django Book Español - Google Drive

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 rápido y ligero es solo para hacer pruebas de manera local yno se debe de usar para producción, ya que no esta probado tan intensivamente como otrosservidores web.

Vistas y URLconfs

Tu primera página hecha con Django: Hola Mundo!Una vez que ya tenemos instalado Django podemos empezar a jugar. Como primera páginavamos 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 páginas. Laprimera 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 lopusiste en un subdirectorio). Con Django, también debes de especificar estas 2 cosas, perode una manera diferente. El contenido de un archivo es renderizado por una función llamadavista, y la URL es especificada por un URLconf. Primero vamos a escribir la función "hola".

Tu primera vistaEn el directorio mysite que hiciste con el comando django­admin startproject, tienes unarchivo llamado views.py. Este módulo de python contendrá las vistas que haremos duranteesta entrada. Nota que cuando abras este archivo por primera vez estará vacío. Además, aDjango no le importa como se llame este archivo pero por convención lo mantendremoscomo views.py.

Nuestra vista "Hola mundo" es muy simple, aquí esta un ejemplo de como sería nuestrafunción:

from django.http import HttpResponse

def hello(request): return HttpResponse("Hola mundo")

Page 12: Django Book Español - Google Drive

Vamos a leer el código línea por línea:Primero, importamos la clase HttpResponse, la cual reside en el módulo django.http.Necesitamos importar esta clase porque la vamos a usar más adelante en nuestro código.Segundo, definimos una función llamada hello ­ la función vista.

Cada función vista recibe al menos un parámetro llamado request por convención. Este esun objeto que contiene información acerca de la petición web que fue disparada por estavista, además este objeto es una instancia de la clase django.http.HttpRequest. En esteejemplo no vamos a hacer nada con request, pero este siempre debe de ser el primerparámetro en cualquier vista.

Nota que el nombre de la función no importa, no tiene que ser llamada de cierta manerapara que Django la reconozca. La estamos llamando hello, porque el nombre claramenteindica la esencia de la vista, pero también pudo ser llamada hola_hermoso_bello_mundo oalgo igual de repulsivo.

La función es un simple "one­liner": Simplemente regresa un objeto de la clase HttpResponseque has inicializado con el texto "Hola mundo".

Aquí la principal lección es esta: una vista es una función de python que toma como primerparámetro un objeto HttpRequest y regresa una instancia de la clase HttpResponse. Para queuna función pueda ser una vista Django, necesita hacer estas 2 cosas. (Claro que hayexcepciones y vamos a ver estas excepciones después).

Si el lector es lo suficiente agudo pudo darse cuenta que este es básicamente el modelocliente­servidor.

Tu primer URLconfHasta es te punto si corres python manage.py runserver otra vez, todavía vas a ver elmensaje "It worked", sin pista alguna de nuestro "Hola mundo". Y esto es porque nuestroproyecto mysite aún no sabe de la existencia de nuestra vista hello. Necesitamos decirle aDjango que estamos activando esta vista en una URL específica. (Continuando con laanalogía de los archivos HTML estáticos, en este momento todavía no hemos subido nuestroarchivo al servidor.) Para enlazar una vista a una URL en particular usando Django, usamosun URLconf.

Un URLconf es como una tabla de contenidos para tu sitio hecho con Django. Básicamentees una tabla de relaciones donde describe que función debe de ser llamada cada vez quevisitan cierta URL. Por ejemplo cuando alguien visite foo llama a la vista foo_view(), quevive en el módulo views.py.

Cuando ejecutaste django‐admin startproject, el script creo un URLconf por tiautomáticamente: el archivo urls.py. Por defecto se ve más o menos así:

Page 13: Django Book Español - Google Drive

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 características comentadas usadas porDjango, para activar estas características es fácil solo tienes que descomentar las líneasnecesarias y listo. Si ignoramos los comentarios entonces tenemos algo más o menos así.

from django.conf.urls.defaults import *

urlpatterns = patterns('',)

Vamos a analizar línea por línea el código. La primera línea importa todos los objetos de elmódulo django.conf.urls.defautls, la cual es la infraestructura de los URLconfs de Django.Esto también incluye una función llamada patterns. La segunda línea llama a la funciónpatterns y salva su resultado en una variable llamada urlpatterns. La función patterns se lepasa un solo argumento ­ una cadena vacía. (Esto se puede usar como prefijo pero loveremos más adelante)

El principal punto a notar aquí es la variable urlpatterns, el cual Django espera encontraren nuestro módulo de URLconfs. Esta variable define las relaciones entre las URLs y lasvistas que manejan estas URLs. Por defecto la URLconf esta vacía. Además si el URLconfesta vacío Django asume que acabas de crear tu proyecto mostrando el mensaje "Itworked!".

Ahora lo único que tienes que hacer es añadir una tupla para definir la relación entre unaURL y una vista.Ejemplo:

from django.conf.urls.defaults import *from mysite.views import hello

urlpatterns = patterns('',

Page 14: Django Book Español - Google Drive

('hello/$', hello),)

Nosotros hemos quitado los comentarios para brevedad, pero si quieres puedes dejarlos.

Hicimos 2 cambios:Primero, importamos la función hello de nuestro módulo mysite.views. Segundo, añadimosla línea ('hello/$', hello), a urlpatterns. A esta línea la vamos a llamar URLpattern.

Ahora vamos a discutir un poco sobre la sintaxis de un URLpattern porque no es obvio aprimera vista. A pesar de que queremos hacer coincidir la URL /hello/, el patrón se ve unpoco 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/quedaría hello/.

Los patrones incluyen un circunflejo ( ) y el signo de dolar ($). Esto son caracteresespeciales de expresiones regulares que tienen un significado especial: El circunflejo ( )significa que "el patrón requiere coincidir desde el inicio de la cadena", por el otro lado elsigno de dolar ($) significa que "requiere que el patrón coincida con el final de la cadena".

Este concepto se puede explicar mejor con un ejemplo. Si en vez del patrón hello/$

hubiéramos usado hello/ (sin el signo de dolar al final), entonces cualquier URL queempiece con /hello/ coincidiría, tal como /hello/foo y /hello/bar y no solamente /hello/.Igualmente si hubiéramos usado la expresión hello/$ sin el circunflejo al principio entoncescoincidiría cualquier cadena que termine en hello/ como /foo/bar/hello/. Si no hubiéramosusado ni el signo de dolar ni el circunflejo solo hello/ entonces coincidiría cualquier cadenaque contenga hello/ tal como /foo/hello/bar. Y es por eso que tan importante usar elcircunflejo y el signo de dolar.

La mayoría de los URLpatterns empezarán con un circunflejo y terminarán con signo dedolar pero es importante saber que también podemos hacer patrones mas sofisticados.

Hasta este momento te estarás preguntando qué pasaría si alguien hiciera una petición a laURL /hello. Porque nuestro URLpattern requiere un slash al final, esa URL no coincidiría. Sinembargo, por defecto cualquier petición que no coincida con URLpattern y no termine con unslash va ser redireccionado a la misma URL con un slash al final. (Esto es regulado por lavariable APPEND_SLASH que puedes encontrar en tu archivo de configuración settings.py.)

Otra cosa que deberías notar acerca de los URLconfs es que hemos pasado la función hellocomo un objeto sin llamar a la función. Esto es una característica clave de python (y demuchos otros lenguajes dinámicos): las funciones son objetos de primera clase, lo quesignifica que puedes pasarlos como si fuera cualquier otra variable.

Para probar nuestros cambios en el URLconf, inicia el servidor de desarrollo de Django,

Page 15: Django Book Español - Google Drive

como lo hiciste anteriormente corriendo el comando (python manage.py runserver). Si lodejaste corriendo esta bien, no es necesario que lo reinicies, el servidor automáticamentedetecta cambios en tu código y recarga lo necesario, entonces no necesitas reiniciar elservidor para ver cambios. El servidor esta corriendo en la dirección http://127.0.0.1:8000/,entonces abre tu navegador web favorito y entra a http://127.0.0.1:8000/hello/. Entoncesdebes de ver el texto "Hola mundo" ­ la salida de tu vista hello.

Felicidades! Has hecho tu primera pagina web con Django.

Nota: Expresiones regularesExpresiones regulares (o regexes) son una manera compacta de especificar patrones enel texto. Mientras las URLconfs de django permiten expresiones regulares arbitrarias parauna poderosa coincidencia de patrones en la URL, probablemente solo uses un pocasexpresiones en la practica. Aqui hay una pequeña selección de las expresiones masusadas:

Expresión Coincide

. (dot) Cualquier carácter.

\d Un solo dígito decimal.

[A‐Z] Cualquier cáracter entre A y Z (uppercase)

[a‐z] Cualquier cáracter entre a y z (lowercase)

[A‐Za‐z] Cualquier cáracter entre a y z (case­insensitive)

+ Uno o mas de la expresión previa (ejemplo: \d+ coincide uno o másdígitos)

[/]+ Uno o mas caracteres hasta (y sin incluir) el slash.

? Cero o una de la expresión previa (ejemplo: \d? coincide cero o undígito)

* Cero o mas de la expresión previa (ejemplo: \d* coincide cero, uno omas de un dígito).

1,3 Entre 1 y 3 (inclusive) de la expresión previa (ejemplo: \d1,3 coincideuno, dos o tres dígitos)

Para mas expresiones regulares ver http://www.djangoproject.com/r/python/re­module/.

Una nota rápida acerca de errores 404Hasta este punto, nuestra URLconf define un solo URLpattern: El único que maneja laspeticiones de la URL /hello/. ¿Pero que pasa cuando lanzas una petición a una URL

Page 16: Django Book Español - Google Drive

diferente?

Para averiguarlo, trata de correr el servidor de desarrollo de django y visitar alguna URLque no tengas en el URLconf, por ejemplo http://127.0.0.1:8000/goodbye/ ohttp://127.0.0.1:8000/hello/subdirectory/, o incluso http://127.0.0.1:8000/. Entonces debesde 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 definidaen el URLconf.

La utilidad de esta paginan va mas allá de un básico mensaje de error 404. Además te diceque URLconf esta usando django y cada patrón de la URLconf. A partir de esa información,deberías de ser capaz de deducir por que la petición a URL arrojo un error 404.

Naturalmente, esta es información sensible y pretendido solo para ti, el desarrollador web.Si este fuera un sitio en producción en Internet, seguramente no querrías que estainformación sea expuesta al publico. Por esta razón, la pagina “Page not found” va a sermostrada solamente si tu proyecto django esta en modo debug. Más tarde vamos a explicarcomo desactivar el modo debug. Por ahora, solo necesitas saber que cada proyecto djangoesta en modo debug la primera vez que es creado, y si el proyecto no esta en modo debug,django mostrara un diferente mensaje.

Page 17: Django Book Español - Google Drive

Una nota rápida acerca del sitio raízComo explicamos en la ultima sección, vas a ver un mensaje de error 404 en el sitio raíz ­­http://127.0.0.1:8000/. Django no añade nada magicamente al sitio raíz; de cualquiermanera esa URL no es ningún caso especial. Esta en tus manos (o mejor dicho en tusdedos) asignar ese URLpattern, justo como cualquier otro URLpattern en tu URLconf.

El URLpattern que coincide con el sitio raíz es exactamente intuitivo, aunque, vale la penamencionarlo. Cuando estés listo para implementar la vista para tu sitio raíz, usa elURLpattern $, que coincide una cadena vacía. Por ejemplo:

from mysite.views import hello, my_homepage_view

urlpatterns = patterns('', ('$', my_homepage_view), # ...)

Como Django Procesa una PeticiónAntes de continuar con nuestra segunda función vista, vamos a pausar un momento yaprender un poco mas acerca de como django trabajo. Específicamente, cuando ves elmensaje “Hello Word” una vez que visitas http://127.0.0.1:800/hello/ en tu navegador webfavorito, ¿Qué es lo que hace django detrás de las escenas?

Todo empieza con el archivo settings. Cuando tu corres python manage.py runserver, elscript 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, todaslas configuraciones estan en mayusculas (o mejor dicho en uppercase): TEMPLATE_DIRS,DATABASE_NAME, etc. La configuración más importante es una llamada ROOT_URLCONF.ROOT_URLCONF le dice a django que modulo de python debe de ser usado para el URLconf deeste sitio.

¿Recuardas cuando django­admin startproject creo los archivos settings.py y urls.py? Elarchivo settings.py autogenerado contiene una configuración ROOT_URLCONF que pordefecto apunta a un archivo urls.py tambien autogenerado. Abre settings.py y mira por timismo; 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 petición para/hello/ ­­ django carga el URLconf que especifa la configuración ROOT_URLCONF. Despuéscheca cada URLpattern en el URLconf, en orden, comparando la URL con los patrones unopor uno, hasta que encuentre uno que coincida. Cuando encuentra uno que coincide, llama a

Page 18: Django Book Español - Google Drive

la función asociada a ese patrón, pasando un objeto HttpRequest como primer parámetro.(Nosotros vamos a cubrir mas especificamente HttpRequest más adelante).

Como vimos en nuestro primer ejemplo, una función vista debe de regresar unHttpResponse. Una vez que la vista regresa el objeto HttpResponse, django se encarga delresto, convierte el objeto a una respuesta HTTP apropiada, con cabeceras y el cuerpo. Enresumen:

1. Una petición entra por /hello/.2. Django determina que URLconf usar en base a la configuración 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 función vista asociada.5. La función 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 básico 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 dinámicoNuestra vista “Hola mundo” fue instructiva en demostrar lo básico de como funcionaDjango, pero no fue un ejemplo de una pagina web dinámica porque el contenido de lapagina es siempre el mismo. Cada vez que visitas /hello/, vas a ver lo mismo; es como sifuera un archivo estatico HTML.

Para nuestra segunda vista, vamos a crear algo mas dinámico, ­­ una pagina web quemuestre la fecha y hora actual. Esto va a ser un agradable y simple paso, porque noenvuelve ninguna base de datos o datos de entrada del usuario ­­ solo despliega la fecha yhora del servidor. Es tan solo un poco mas emocionante que el “Hello world”, pero va ademostrar mas conceptos que nuestro ejemplo pasado.

Esta vista necesita 2 cosas: Calcular la fecha y hora actual y regresar un HttpResponseconteniendo ese valor. Si has tenido experiencia con python, probablemente sabes quepython incluye el modulo datetime para calcular fechas. Aquí esta como lo vamos a usar:

>>> import datetime>>> now = datetime.datetime.now()>>> nowdatetime.datetime(2008, 12, 13, 14, 9, 39, 2731)>>> print now2008‐12‐13 14:09:39.002731

Esto es lo suficientemente simple y no tiene nada que ver con Django. Es solo código escritoen python. (Nosotros queremos hacer énfasis que es “solo código python” vs. código que es

Page 19: Django Book Español - Google Drive

especifico de django. Como estas aprendiendo python, nosotros queremos que seas capazde usar tu conocimiento en otros proyectos que usen python pero que no necesariamenteusen django.)

Para hacer que nuestra vista despliege la fecha y hora actual, lo unico que necesitamoshacer es enganchar datetime.datetime.now() en la vista y regresar un objeto HttpResponse.Aquí esta como quedaría:

from django.http import HttpResponseimport 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 función debe de residir en views.py. Nota que hemosescondido la vista hello en este ejemplo por cuestiones de brevedad, pero así es como severia nuestro views.py hasta ahora:

from django.http import HttpResponseimport 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 código de ejemplos anteriores, excepto cuandosea necesario. Así que deberías de ser capaz de distinguir el nuevo código vs. el viejocódigo a partir del contexto de la lectura.)

Ahora vamos a ver paso por paso los cambios que hemos hecho con views.py para poner lavista current_datetime.

Hemos añadido import datetime al principio del módulo para poder calcular fechas. La nueva función current_datetime calcula la fecha y hora actual, como un objeto

datetime.datetime y lo guarda en una variable local llamada now. La segunda línea de código de nuestra vista, construye la respuesta HTML usando

“format­string” de python (o formateo de cadenas de python). El %s en el stringrepresenta un “placeholder” (o parámetro de sustitución) y el simbolo de % despuésdel string significa “Reemplaza el %s con el valor de la variable now.” La variable now

Page 20: Django Book Español - Google Drive

es técnicamente un objeto datatime, no un string, pero el formato %s lo convierte aun string, cuya representación es algo como “2008‐12‐13 14:09:39.002731”. Entonceseste sería el resultado en nuestro string que contiene HTML “<html><body>It is now2008‐12‐13 14:09:39.002731.</body></html>”.

(Si, nuestro HTML es inválido, pero estamos tratando de mantener el ejemplo simpley corto).

Finalmente, la vista regresa un objeto HttpResponse que contiene la respuestagenerada ­­ tal como lo hicimos en la vista hello.

Despues de añadir nuestro código a views.py, añadir el URLpattern a urls.py para decirle adjango qué URL debería de manejar esta vista. Algo como /time/ tendría más 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 función current_datetime al iniciodel modulo. Segundo, y más importante, añadimos 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 visitamoshttp://127.0.0.1:8000/time/ en tu navegador favorito y entonces deberías de ponder ver lafecha y hora actual.

La zona horaria de djangoDependiendo 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 esAmerica/Chicago. (Bueno, tenía que tener alguna una zona horaria por defecto y esa zonahoraria 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 CouplingAhora es un buen momento para remarcar una filosofía clave detrás del URLconfs y dedjango en general: El principio de loose coupling (o asociación difusa). Para ponerlo simple,loose coupling es un enfoque de desarrollo de software que aprecia la importancia de hacerpiezas intercambiables de software. Si dos piezas de software son loosely coupled (o

Page 21: Django Book Español - Google Drive

asociadas difusamente), entonces los cambios hechos a una pieza de software tiene unefecto poco o nulo sobre la otra pieza de software.

Las URLconfs de django son un buen ejemplo de este principio en la práctica. En unaaplicación web hecha con django, las definiciones de las URLs y las vista son llamadasloosely coupled (difusamente asociadas); eso es, la desición de poder cambiar la URL y lavista 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 parala aplicación ­­ digamos, moverla de /time/ a /current‐time/ ­­ nosotros podemos hacer un rápidocambio en el URLconf, sin tenernos que preocupar acerca de la vista. Similarmente, si nosotrosquisieramos cambiar la vista ­­ alterando su lógica de algún modo ­­ nosotros podríamos hacer eso sintener que alterar la URL a la cual está sujeta.

Además, si nosotros queremos exponer la fecha actual en diferentes URLs, nosotrospodemos hacer esto fácilmente editando el URLconf, sin tener que tocar nada del código dela vista. Es este ejemplo, nuestra vista current_datetime esta disponible en dos URLs. Es unejemplo artificial, pero esta técnica puede volverse bastante útil.

urlpatterns = patterns('', ('hello/$', hello), ('time/$', current_datetime), ('another‐time‐page/$', current_datetime),)

URLconfs y vistas están difusamente asociados y vamos a continuar haciendo énfasis a laimportancia de esta filosofía a través de este libro.

Tu tercera vista: URLs dinámicasEn nuestra vista current_datetime, el contenido de la pagina ­­ la fecha y hora actual ­­ esdinamica, pero la URL (/time/) fue estatica. En la mayoría de las aplicaciones webdinamicas, una URL contiene parametros que afectan la salida de la página. 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 uncierto número de horas. El objetivo es hacer un sitio de tal manera que la página/time/plus/1/ despliege la fecha y hora una hora en el futuro, la página /time/plus/2/despliege la fecha y hora 2 horas en el futuro, la página /time/plus/3/ despliege la fecha yhora 3 horas en el futuro y así sucesivamente.

Un novato tal vez pensaría en codificar una vista separada para cada desplazamiento, lacual tal vez resulte en un URLconf como este:

Page 22: Django Book Español - Google Drive

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 sería defunciones redundantes, si no que además la aplicación esta fundamentalmente limitada asoportar solo un rango predefinido de horas ­­ uno, dos, tres o cuatro horas. Si nosotrosdecidimos crear una pagina que despliegue el tiempo cinco horas en el futuro, tendríamosque crear una vista separada y agregar a nuestro URLconf el URLpatter necesario, ademásde la duplicación. Entonces necesitamos hacer un poco de abstracción aquí.

Un poco acerca de pretty URLs

Si tu has experimentado en otra plataforma de desarrollo web, tal como PHP o Java, talvez estes pensando “Hey, ¡vamos a usar un query string!” ­­ algo como/time/plus?hours=3, en cual las horas seran designadas por el parámetro hours en elquery 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 lasfilosofias 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, fácil de pasarsela a alguien y masbonita que un query string. Pretty URLs (o URLs bonitas o amigables) son unacaracterística de la calidad de una aplicación Web.

El sistema de URLconf de django fomenta el uso de pretty URLs haciendo más fácil el usode pretty URLs que no hacerlo.

Entonces, ¿Como diseñamos nuestra aplicación para que maneje desplazamientosarbitrarios? La clave es usar una wildcard (o comodín) en el URLpatterns. Comomencionamos anteriormente, un URLpattern es una expresión regular; y por lo tanto,podemos usar el patrón \d+ para coincidir uno o mas dígitos:

urlpatterns = patterns('', # ... (r'time/plus/\d+/$', hours_ahead), # ...)

(Nosotros estamos usando #... para implicar que pueden haber otros URLpatterns quenosotros quitamos de este ejemplo por cuestiones de simplicidad.)

Page 23: Django Book Español - Google Drive

Este nuevo URLpatter va a coincidir cualquier URL como /time/plus/2/, /time/plus/25/ oincluso /time/plus/100000000000/. Pensadolo bien, vamos a limitar el desplazamientomaximo permitido a 99 horas. Esto significa que queremos permitir solo uno o dos dígitos ­­y en nuestra expresión regular esto se traduciría como \d1,2.

(r'time/plus/\d1,2/$', hours_ahead),

NotaCuando construimos aplicaciones web, siempre es importante considerar hasta la más descabelladaentrada posible, y decidir si nuestra aplicación debería soportar esa entrada o no. Nosotros decidimoslimitar el desplazamiento a 99 horas y evitarnos posibles entradas descabelladas.

Un detalle importante que tenemos que introducir aquí es el carácter r antes del inicio delstring que contiene la expresión regular. Esto le dice a python que el string es un “rawstring” (o cadena cruda) ­­ cuyo contenido no debe de interpretar los backslashes (odiagonales inversas \). En los string normales, los backslashes son usados para representarcaracteres especiales ­­ tal como en el string “\n”, el cual es un string de un solo carácterque contiene una nueva linea. Cuando añades una r antes de una cadena lo que haces esconvertir esa cadena un “raw string” (o cadena cruda), y entonces python no aplica elescapado de caracteres especiales. ­­ entonces, r”\n” es ahora un string de 2 caracteresque contiene un literalmente un backslash (\) y una n. Existe una colisión natural entre eluso de backslashes en los string normales de python y los backslashes que necesita lasexpresiones regulares, por eso recomendamos fuertemente el uso de “raw strings”(cadenas crudas) cuando estas escribiendo alguna expresión regular. Desde ahora, todos losURLpatterns serán raw strings.

Ahora que hemos designado una wildcard (comodín) para la URL, necesitamos una manerade pasar los datos que capture esa wildcard a nuestra vista, para que podamos usar unasola vista para un numero arbitrario de horas desplazadas. Nosotros hacemos esto poniendoparentesis al rededor del patrón que queremos capturar en el URLpattern. En el caso denuestro ejemplo, nosotros queremos salvar cualquier numero que fue introducido en la URL,entonces vamos a poner parentesis al rededor de el \d1,2, de la siguiente manera:

(r'time/plus/(\d1,2)/$', hours_ahead),

Si estas familiarizado con expresiones regulares, entonces te sentiras como en casa;Nosotros estamos paréntesis para capturar los datos que coincidan en el texto.

El URLconf, incluyendo las 2 vistas previas, quedaría así:

from django.conf.urls.defaults import *

Page 24: Django Book Español - Google Drive

from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = patterns('', (r'hello/$', hello), (r'time/$', current_datetime), (r'time/plus/(\d1,2)/$', hours_ahead),)

Una vez hecho esto, vamos a escribir nuestra vista hours_ahead.

Orden de codificaciónEn este ejemplo, nosotros escribimos primero el URLpattern y despues la vista, pero enlos ejemplos previos, nosotros escribimos primero la vista y después el URLpattern. ¿Cualtécnica es mejor?

Bueno, cada desarrollador es diferente.

Si eres el tipo de persona que ve todo de manera muy general, tal vez tenga más sentidopara ti escribir todas las URLpatterns en tu aplicación al mismo tiempo, al inicio de tuproyecto y luego codificar las vistas. Esto tiene la ventaja de darte una lista de tareas quedebes de hacer y esencialmente defines los parámetros requeridos por las vistas que vasa necesitar escribir.

Si por lo contrario eres más del tipo de programador que le gusta empezar de abajo haciaarriba, tal vez prefieras escribir tus vistas primero y después anclarlas a una URL. Estotambién esta bien.

Al final, usas la técnica a la que mejor se adapte tu cerebro. Ambos enfoques sonperfectamente válidos.

hours_ahead is muy similar a la vista current_datetime que escribimos antes, con unadiferencia clave: toma un argumento extra, el numero de horas a desplazar. Aquí estacomo se vería el código:

from django.http import Http404, HttpResponseimport 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)

Page 25: Django Book Español - Google Drive

Vamos a explorar este código línea por línea: La vista, hours_ahead, toma dos parámetros: request y offset, que son la petición 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 unobjeto HttpRequest como su primer parámetro.

offset es el string capturado por los parentesis en el URLpattern. Por ejemplo,si la URL fuera /time/plus/3/, entonces el offset (desplazamiento) sería lacadena ‘3’. Si la URL fuera /time/plus/21/, entonces el offset sería 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 serán objetos Unicode, noplanas y simples bytestrings, pero no te preocupes sobre esto, es solo unaaclaración por el momento.)

Nosotros decidimos a nuestra variable offset, pero tu puedes nombrarlacomo tu quieras, claro siempre y cuando sea un identificador válido enpython. El nombre de la variable no importa; todo lo que importa es elsegundo argumento, después de request. (También es posible usar unkeyword (palabra clave o argumento opcional), en vez de un argumentoposicional en el URLconf. Vamos a cubrir esto en “Vistas y URLconfsavanzados”)

La primera cosa que hacemos en la vista es llamar a la función int() con offsetcomo parámetro. Esto trata convertir el string a un entero.

Nota que python va a lanzar una excepción ValueError si llamas a int() con unparámetro que no puede ser convertido a un entero, como por ejemplo el string ‘foo’.En este ejemplo si encontramos una excepción de tipo ValueError, nosotros lanzamosuna excepción django.http.Http404, la cual, como te puedes imaginar, resulta en unapágina de error 404 “Page not found”.

Lectores astutos se preguntaran: ¿Como podríamos alcanzar el caso dondeValueError es lanzado, si de cualquier modo, dada la expresión regular en nuestroURLpattern ­­ (\d1,2) ­­ captura solamente digitos, y por lo tanto offset solo va aser un string compuesto de digitos? La respuesta es, no vamos a hacerlo, por que elURLpattern provee una modesto pero util nivel de validación, pero aun así seguimoschecando por el error ValueError en caso que esta vista llege a ser llamada dealguna otra manera. Además es una buena practica implementar vistas de talmanera que no tengan que hacer ninguna suposición de los parametros que van arecibir. Loose coupling (asociación difusa), ¿recuerdas?

En la siguiente línea de vista, nosotros calculamos la fecha y hora actual y añadimosel número apropiado de horas. Como ya hemos visto datatime.datetime.now() de lavista current_datetime; el nuevo concepto aquí es que puedes ejecutar aritmética defecha/hora creando un objeto datetime.timedelta y sumandolo con un objetodatetime.datetime. Nuestro resultado es almacenado en la variable dt.

Esta línea támbien muestra por que llamamos a int() con offset ­­ la funcióndatetime.timedelta requiere que el parámetro hours sea un entero.

Luego, construimos el HTML que desplegara esta vista, tal como hicimos en la vista

Page 26: Django Book Español - Google Drive

current_datetime. Una pequeña diferencia en esta línea comparada con los anteriores“string format” (formateos de cadenas) que hemos hecho, es que ahora hay dossimbolos %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 queya este corriendo), y visitamos http://127.0.0.1:8000/time/plus/3/ para verificar quefuncione. Luego probamos http://127.0.0.1:8000/time/plus/5/. Despueshttp://127.0.0.1:8000/time/plus/24/. Finalmente, visitamoshttp://127.0.0.1:8000/time/plus/100/ para verificar que el patron en tu URLconf solo aceptenumeros de uno o dos digitos; Django debería desplegar el error “Page not found” (paginano encontrada) en este caso, justo como lo vimos en la sección “Una nota rápida acerca delas errores 404”. La URL http://127.0.0.1:8000/time/plus/ (sin ninguna hora designada)tambien debería de arrojar un error 404.

Las paginas de errores amigables de djangoToma un momento para admirar la fina aplicación que hemos hecho hasta el momento …ahora ¡vamos a romperla! Vamos a introducir deliberadamente errores en nuestro archivoviews.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 página de error conuna sustancial cantidad de información, incluyendo un mensaje de error TypeErrordesplegado al mero inicio: "unsupported type for timedelta hoyrs component: unicode"

¿Qué paso? Bueno, la función datetime.timedelta espera que el parámetros hours sea unentero, y nosotros comentamos un poco de código que convertia offset en un entero. Esocauso que datetime.timedelta lanzara el TypeError. Es el típico error que le ocurre acualquier programador en algún punto.

El punto de este ejemplo fue demostrar las paginas de error de Django. Tomate tiempo paraexplorar la pagina de error y conocer un poco la variada información que ofrece.

Aquí hay un par de cosas que notar: Al principio de la página, vas a ver información clave acerca de la excepción: el tipo

de la excepción, los parametros de la excepción (en este caso el mensaje"unsupported type"), el archivo en el que fue lanzada la excepción y el número delinea.

Debajo de la información clave de la excepción, la página muestra todo el

Page 27: Django Book Español - Google Drive

"traceback" (el traceback es el rastro de origen de la excepción). Esto es similar alestandar traceback de la consola interactiva de python, excepto que esta es masinteractiva. Para cada nivel ("frame") en la pila, django despliega el nombre delarchivo, el nombre de la función o metodo, el número de linea y el código fuente deesa línea.

Da click en la línea "source code" (en gris oscuro) y vas a ver varias lineas desdeantes y después de la línea erronea, para darte un contexto.

Da click en "Local vars" debajo de cualquier frame para ver una tabla de todas lasvariables locales y sus valores, en ese frame en el momento justo donde laexcepción fue lanzada. Esta información de depuración 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 tracebackva a cambiar a una versión alternativa que puede ser copiada y pegada fácilmente.Usa esto cuando quieras compartir el traceback de la excepción con otras personaspara obtener soporte técnico ­­ como en el canal IRC de django o en la lista decorreos de django.

Siguiente, la sección "Request Information" (información de la petición) incluyeinformación acerca petición web que ingresa: GET, POST, COOKIE, meta información,tales como cabeceras CGI y FILES. El apendice G tiene una completa referencia detoda la información que contiene un objeto Request.

Debajo de la sección "Request information", la sección de "Settings" (ajustes) listatodos los ajustes de esta particular instalación de django. (Nosotros ya mencionamosROOT_URLCONF, y vamos a mostrarte varios ajustes de django a lo largo del libro.Todos los ajustes son cubiertos en detalle en el apéndice D.)

La página de error de django es capaz de desplegar mas información en ciertos casosespeciales, tal como el caso de error de sintaxis. Vamos a ver eso mas adelante, cuandohablemos sobre el sistema de "templates" (plantillas) de django.

Por ahora, descomenta las lineas de offset = int(offset) para que la vista funcioneapropiadamente otra vez. ¿Eres el tipo de programador que le gusta depurar con la ayudade sentencias print cuidadosamente colocadas? Si es así, puedes usar la pagina de error dedjango para hacer eso. ­­ solo que sin las sentencias print. En cualquier punto de tu vista,temporalmente inserta assert False para lanzar una página de error. Entonces, puedes verlas variables locales y estado del programa. Aquí hay un ejemplo, usando la vistahours_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)

Page 28: Django Book Español - Google Drive

Finalmente, es obvio que mucha de esta información es sencible ­­ expone todas las tripasde tu código y de la configuración de django ­­ y sería tonto mostrar esta información enInternet. Una persona maliciosa puede intentar usar ingeniería­inversa en tu aplicación webpara hacer cosas sucias. Por esa razón, la página de error de django solo se muestracuando la aplicación esta en modo debug (depuración). Vamos a enseñarte a comodesactivar en "Django en producción". Por ahora, solo sabes que cada proyecto django estaen modo debug automaticamente cuando lo empiezas. (¿Te suena familiar? la página deerror "Page not found", descrita al inicio de este capítulo, trabaja de la misma manera.)

Plantillas (capitulo 4, zerokillex)En el capítulo anterior, pudo haber notado algo especial en cómo se devolvió el texto ennuestro ejemplo de la vista. Es decir, el HTML fue incrustrado directamente en el códigopython 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 técnica fue conveniente para el propósito de la explicación en como las vistastrabajan, no es una buena idea incrustrar HTML directamente en nuestras vistas. He aquípor qué:

Cualquier cambio en el diseño de la página requiere un cambio en el código python.El diseño de un sitio web tiende a cambiar con más frecuencia que el códigosubyacente de python, por lo que sería conveniente si el diseño pudiera cambiar sinnecesidad de modificar el código python.

Escribir código python y diseñar en HTML son dos diciplina distintas, y muchosentornos profesionales de desarrollo web dividen estas responsabilidades entredistintas personas (o incluso entre departamentos). Los diseñadores y autoresHTML/CSS no deberían estar obligados editar el código python para llevar a cabo sutrabajo.

Es más eficiente si los programadores pueden trabajar el código python y losdiseñadores trabajar con la plantilla al mismo tiempo, en lugar de una personaesperar que otro termine editar un solo archivo que contiene python y HTML.

Por estas razones, es mucho más limpio y mantenible separar el diseño de páginas del código python.Esto lo podemos lograr con el sistema de plantillas de Django, el cual discutiremos en este capítulo.

Fundamentos del sistema de plantillasUna plantilla Django es una cadena de texto destinado a separar la presentación del documento de susdatos. Una plantilla define los marcadores de posición y varios fragmentos de la lógica básica (etiquetasde plantillas) que regulan como el documento debe ser mostrado. Usualmente, las plantillas sonutilizadas para producir HTML, pero las plantillas Django son igualmente capaces de generar cualquier

Page 29: Django Book Español - Google Drive

formato basado en texto.

Comencemos con una plantilla de ejemplo. La siguiente plantilla Django describe una página HTML queagradece a una persona al completar una orden con una empresa. Piense en ello como un modelo decarta:

<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 toship 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 básico 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”. (¿Cómo indicamos los valoresde las variables? Más adelante hablaremos de ello.)

Cualquier texto que esta rodeado de una llave y el signo de porcentaje (por ejemplo, % ifordered_warranty %) es una etiqueta de plantilla. La definici’on de una etiqueta es bastanteamplio: una etiqueta le dice al sistema de plantilla “haz algo”.

Esta plantilla de ejemplo contiene una etiqueta for (% for item in item_list %) y unaetiqueta if (% if ordered_warranty %).

Una etiqueta for funciona muy similar a la declaración for en python, permitiendo iterar sobrecada elemento de una secuencia. Una etiqueta if, como se puede esperar, actúa como unadeclaración lógica. En este caso particular, la etiqueta comprueba si el valor de la variable

Page 30: Django Book Español - Google Drive

ordered_warranty evalúa a True. Si lo hace, el sistema de plantilla mostrará todo entre % ifordered_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 párrafo de esta plantilla contiene un ejemplo de un filtro, que es laforma más 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, indicandoal filtro date el argumento “F j, Y”. El filtro date formatea las fechas en un formato dado, segúnlo especificado en el argumento. Los filtros estan enlazado utilizando el carácter de barra vertical(|), como referencia a las tuberías (pipe) en Unix.

Cada plantilla Django tiene acceso a varias etiquetas y filtros incorporadas, de los cuales muchos sediscuten en las próximas secciones. El Apéndice F contiene una lista completa de etiquetas y filtros, y esrecomendable familiarizarse con la lista para que conozca lo que es posible. También es posible crear suspropios filtros y etiquetas; más detalles en el capítulo “Plantillas avanzadas”.

Utilizando el sistema de plantillaEntremos en el sistema de plantillas de Django para que puedas ver cómo funciona — pero todavía novamos a integrarlo en la vista que creamos en el capítulo anterior. Nuestro objetivo aquí es mostrarcómo el sistema funciona, independientemente del resto de Django. (Dicho de otro modo:habitualmente utilizarás el sistema de plantilla dentro de una vista de Django, pero queremos dejar claroque el sistema de plantilla es sólo una librería de python que se puede utilizar en cualquier lugar, no sóloen las vistas de Django.)

Esta es la forma más básica que puedes utilizar el sistema de plantilla de Django en el código python:1. Crear un objeto Template proporcionando el código puro de la plantilla como una cadena de

texto.2. Invocar el método render() del objeto Template con un conjunto de variables (el contexto).

Esto devuelve una plantilla completamente representada como una cadena, con todas susvariables y etiquetas de plantilla evaluada de acuerdo al contexto.

En código, 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 más detalle.

Creando objetos TemplateLa forma más fácil de crear un objeto Template es con una instancia directamente de ella. La claseTemplate reside en el módulo django.template, y el constructor toma un argumento, el código puro dela plantilla. Veamos en el intérprete interactivo de python cómo esto funciona en código.

Desde el directorio del proyecto mysite creado por django‐admin.py startproject (como explicó en elcapítulo 2: Iniciando), escribe python manage.py shell para iniciar el intérprete interactivo.

Page 31: Django Book Español - Google Drive

Un símbolo especial de pythonSi usted antes ha utilizado python, puede que se pregunte por qué estamos utilizando pythonmanage.py shell en lugar de sólo python. Ambos comandos inician el intérprete interactivode python, pero el comando manage.py shell tiene una importante distinción: antes deiniciar el intérprete, este le dice a Django cuál archivo de configuración utilizar. Muchas partesde Django, incluyendo el sistema de plantilla, se basan en tus configuraciones, y no seráscapaz de utilizarlos a menos que el framework conozca cual configuración utilizar.

Si tienes curiosidad, he aquí cómo funciona en el trasfondo. Django busca en el entorno unavariable llamada DJANGO_SETTINGS_MODULE, que debe estar declarada a la ruta de importaciónde tu settings.py. Por ejemplo, DJANGO_SETTINGS_MODULE podría estar establecido amysite.settings, asumiendo que mysite esta en la ruta de python. Cuando se ejecutapython manage.py shell, el comando se encarga de establecer DJANGO_SETTINGS_MODULE porti. Le animamos a que utilice python manage.py shell en estos ejemplos con el fin deminimizar 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 yconfigures manualmente DJANGO_SETTINGS_MODULE en tu archivo .bash_profile u otroarchivo de configuración del entorno de la consola.

Repasemos algunos conceptos básicos del sistema de plantilla:

>>> from django.template import Template>>> t = Template('My name is name .')>>> print t

Si usted está siguiendo de forma interactiva, verás 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 objetoTemplate en python, si te interesa saberlo).

Cuando se crea un objeto Template, el sistema de plantilla compila el código crudo en uno interno, deforma optimizada, listo para reproducir. Pero si el código de tu plantilla incluye errores de sintaxis, lainvocación a Template() levantará una excepción 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 término “block tag” aquí se refiere a % notatag %. “Block tag” y “template tag” son sinónimos. Elsistema levanta una excepción TemplateSyntaxError en cualquiera de los siguientes casos:

Etiquetas no válidas Argumentos no válidos para etiquetas válidas

Page 32: Django Book Español - Google Drive

Filtro no válido Argumentos no válidos para filtros válidos Sintaxis de plantilla no válido Etiquetas sin cerrar (para etiquetas que requieren etiquetas de cierre)

Interpretando plantillasUna vez obtienes un objeto Template, puedes pasarle datos indicando un contexto. Un contexto essimplemente un conjunto de nombres de variables en la plantilla y sus valores asociados. Una plantillalas utiliza para llenar sus variables y evaluar sus etiquetas.

Un contexto es representado en Django por la clase Context, que reside en el módulo django.template.Su constructor toma un argumento opcional: un diccionario de claves asociadas a valores. Ejecute elmétodo 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 utilizalos objetos Unicode en lugar de cadenas normales en todo el framework. Si entiendes las repercusionesde ello, sé agradecido por los detalles sofisticados que Django hace en el trasfondo para que funcione. Sino entiendes las repercusiones, no te preocupes por ahora, sólo sepa que el soporte de Django paraUnicode hace que sea relativamente indoloroso el soporte de tus aplicaciones con una ámplia variedad deconjuntos de caracteres más allá de los básicos “A­Z” del confunjo de caracteres ASCII.

Diccionarios y contextosUn diccionario en python es una correspondencia entre claves conocidas y valores de las variables. Uncontexto es similar a un diccionario, pero un contexto proporciona funcionalidades adicionales, comose explica en el capítulo “Plantillas avanzadas”.

Los nombres de variables deben comenzar con una letra (A­Z o a­z) y puede contener letras, dígitos,guiones, y puntos. (Los puntos son un caso especial, en un momento llegaremos.) Los nombres devariables se distinguen entre minúsculas y mayúsculas. He aquí un ejemplo de la compilación yrepresentación de una plantilla, utilizando una plantilla similar a la del comienzo de este capítulo.

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

Page 33: Django Book Español - Google Drive

... 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 OutdoorEquipment. It's scheduled to\nship on April 2, 2009.</p>\n\n\n<p>Youdidn't order a warranty, so you're on your own when\nthe productsinevitably 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 módulo

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 múltiples líneas; en cambio, lascadenas entre comillas simples no admite múltiples líneas.

A continuación, creamos un objeto Template, t, proporcionando raw_template al constructorTemplate.

Importamos el módulo datetime de la librería estándar de python, ya que lo necesitamos en lasiguiente sentencia.

Luego creamos el objeto c de Context. El constructor Context toma un diccionario de pythonque 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 método render() en nuestro objeto Template pasándole el contexto.Este devuelve la plantilla analizada — es decir, se reemplazan las variables de la plantilla con elvalor actual de las variables, y ejecuta las etiquetas de la plantilla.

Note que el párrafo “You didn’t order a warranty” fue mostrado porque la variableordered_warranty fue evaluado como falso (False). También notar que la fecha, April 2, 2009, esmostrada de acuerdo a la cadena de formato ‘F j, Y’. (Más adelante explicaremos la cadena deformato para el filtro date.)

Si eres nuevo en python, se estará preguntando por qué esta salida incluye el carácter salto delínea —o new line— (‘\n’) en lugar de mostrar el salto. Es debido a una situleza en el intérpreteinteractivo de python: la invocación de t.render(c) devuelve una cadena, y por defecto elintérprete interactivo muestra la representación de la cadena, en lugar del valor impreso de lacadena. Si deseas ver la cadena con los saltos de líneas como realmente deben en lugar de loscaracteres ‘\n’, utilice la sentencia print: print t.render(c).

Estos son los fundamentos del uso del sistema de plantillas en Django: sólo escribe una plantilla entexto, crea un objeto Template, crea un contexto Context, e invoca el método render().

Page 34: Django Book Español - Google Drive

Múltiples contextos, la misma plantillaUna vez tengas un objeto Template, se puede procesar múltiples contextos a través de este. Porejemplo:

>>> 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 múltiples contextos utilizando la misma plantilla como en el ejemplo, esmás eficiente crear un objeto Template una vez, y luego invocar múltiples veces render():

# Mal usofor name in ('John', 'Julie', 'Pat'): t = Template('Hello, name ') print t.render(Context('name': name))

# Buen usot = Template('Hello, name ')for name in ('John', 'Julie', 'Pat'): print t.render(Context('name': name))

El parseo de plantillas en Django es bastante rápido. En el trasfondo, la mayoría del parsing se produce através de una simple expresión regular. Este esta marcado por una gran diferencia con los motores deplantillas basado en XML, que incurren en el exceso de parsing XML y tiende ser por magnitud más lentoque el sistema de plantilla de Django.

Búsqueda de variable en el contextoEn los ejemplos hasta el momento, hemos pasado simples valores en los contextos — mayormentestrings, en adición a un datetime.date. Sin embargo, el sistema de plantillas maneja elegantementeestructuras de datos más complejos, tales como listas, diccionarios, y objetos personalizados.

El punto clave para navegar sobre estructuras de datos complejos en las plantillas de Django es elcarácter de punto (.). Utilizando el punto puedes accesar a las claves de diccionarios, atributos, métodos,o los índices de un objeto.

Esto se ilustra mejor en varios ejemplos. Por ejemplo, supongamos que pasamos un diccionario a unaplantilla. 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.')

Page 35: Django Book Español - Google Drive

>>> 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 objetodatetime.date contiene los atributos year, month, y day, con el punto puedes acceder estos atributos enla plantilla de Django:

>>> from django.template import Template, Context>>> import datetime>>> d = datetime.date(1993, 5, 2)>>> d.year1993>>> d.month5>>> d.day2>>> 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 aobjetos 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 también pueden acceder a métodos en los objetos. Por ejemplo, en python cada string tienelos métodos upper() e isdigit(), y puedes invocarlos en las plantillas de Django utilizando la mismasintaxis de punto:

>>> from django.template import Template, Context>>> t = Template(' var ­­ var.upper ­­ var.isdigit ')>>> t.render(Context('var': 'hello'))u'hello ­­ HELLO ­­ False'

Page 36: Django Book Español - Google Drive

>>> t.render(Context('var': '123'))u'123 ­­ 123 ­­ True'

Note que no se incluye los paréntesis en la invocación de los métodos. Además, no es posible pasarargumentos a los métodos; solo puedes invocar métodos que no requieren argumentos. (Luegoexplicarémos esta filosofía en este capítulo.)

Finalmente, los puntos también 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 causaríaun error TemplateSyntaxError.

Las listas de pythonUn recordatorio. Las listas de python comienza por el índice 0.

La búsqueda del punto puede resumirse así: cuando el sistema de plantilla encuentra un punto en elnombre de la variable, este intentará los siguientes pasos, en este orden:

1. Búsqueda en diccionario (ejemplo, foo[“bar”])2. Búsqueda por atributo (ejemplo, foo.bar)3. Invocación de método (ejemplo, foo.bar())4. Búsqueda por índice (ejemplo, foo[2])

El sistema utiliza el primer tipo de busqueda que funcione. Es un corto circuito logístico. El punto sepuede anidar en múltiples niveles de profundidad. El siguiente ejemplo utiliza person.name.upper ,que se traduce a una búsqueda en un diccionario y luego una llamada al método upper():

>>> from django.template import Template, Context>>> person = 'name': 'Sally', 'age': '43'>>> t = Template(' person.name.upper is person.age yearsold.')>>> c = Context('person': person)>>> t.render(c)u'SALLY is 43 years old.'

Comportamiento de los métodosLas invocaciones de métodos son un poco más complejas que los demás patrones de búsquedas. He aquíalgunas cosas a tener en cuenta:

Si durante la búsqueda de un método, el método produce una excepción, la excepción sepropagará a menos que la excepción tenga el atributo silent_variable_failure cuyo valor es True.

Page 37: Django Book Español - Google Drive

Si la excepción tiene el atributo silent_variable_failure, la variable en la plantilla se proyectacomo un string vacío, 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 invocación a un método sólo funcionará si el método no requiere argumentos. De locontrario, el sistema pasará al siguiente tipo de búsqueda (índices de listas).

Obviamente, algunos métodos tienen efectos secundarios, y sería lo más tonto, y posiblementeincluso un fallo de seguridad, permitir al sistema de plantillas acceder a ellos.

Digamos, por ejemplo, tienes un objeto BankAccount que tiene un método delete(). Si unaplantilla incluye algo como account.delete , donde account es un objeto BankAccount, elobjeto sería eliminado cuando la plantilla se analiza.

Para evitar esto, establezca el atributo alters_data de la función.

def delete(self): # Delete the accountdelete.alters_data = True

El sistema de plantillas no ejecutará cualquier método marcado de esta forma. Continuando conel ejemplo anterior, si una plantilla incluye account.delete y el métdo delete() tiene elatributo alters_data = True, entonces el método delete() no será invocado cuando la plantilla seanaliza. En su lugar, se producirá un error silenciosamente.

¿Cómo se manejan las variables no válidas?Por defecto, si una variable no existe, el sistema de plantilla lo presenta como un string vacio, fallandosilenciosamente. Por ejemplo:

>>> from django.template import Template, Context>>> t = Template('Your name is name .')>>> t.render(Context())

Page 38: Django Book Español - Google Drive

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 excepción, ya que está diseñada para serresistente a un error humano. En este caso, todas las búsquedas fallarón porque los nombres de lasvariables son incorrectos o no coinciden con las mayúsculas y minúsculas. En el mundo real, esinaceptable para un sitio web que se vuelva inaccesible debido a pequeños errores sintácticos.

Jugando con objetos Context

La mayoría de las veces, instanciarás los objetos Context pasando un diccionario completo a Context().Pero también puedes agregar y eliminar elementos del objeto Context una vez ha sido instanciadoutilizando la sintaxis estándar 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 básicas de las plantillasComo hemos mencionado anteriormente, el sistema de plantillas viene con etiquetas y filtrosincorporados. En las secciones siguientes se proporciona un resumen de los filtros y etiquetas máscomunes.

Etiquetas

if / elseLa etiqueta % if % evalúa una variable, y si dicha variable es “True” (es decir, que existe, no estavacía, y no es un boolean False), la plantilla mostrará todo entre % if % y % endif %. Por ejemplo:

Page 39: Django Book Español - Google Drive

% 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 pythonEn python y en el sistema de plantillas de Django, los siguientes objetos evalúan a False en elcontexto de Boolean:

Una lista vacía ([ ]) Una tupla vacía (( )) Un diccionario vacío ( ) Un string vacío ('') 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 demás evalúa a True.

La etiqueta % if % acepta operadores and, or, o not para comprobar múltiples variables, o para negaruna 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 %

Page 40: Django Book Español - Google Drive

% if athlete_list and not coach_list % There are some athletes and absolutely no coaches.% endif %

La etiqueta % if % no permite cláusulas and y or dentro de la misma etiqueta, ya que el ordenlogístico sería ambiguo. Por ejemplo, esto no es válido:

% if athlete_list and coach_list or cheerleader_list %

El uso de los paréntesis para controlar el orden de las operaciones no es adimisible. Si ves que necesitasparéntesis, se recomienda realizar la operación de la plantilla y pasar el resultado como una variablededicada 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 %

Múltiples usos de los mismos operadores lógicos están bien, pero no puedes combinar diferentesoperadores. Por ejemplo, lo siguiente es válido:

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

Asegúrese de cerrar cada etiqueta % if % con un % endif %. De lo contrario, Django lanzará unerror TemplateSyntaxError.

forLa etiqueta % for % permite iterar sobre cada elemento de una secuencia. Al igual que la sentenciafor de python, la sintaxis es for X in Y, donde Y es la secuencia a recorrer y X es el nombre de la variablea utilizar en un punto determinado del bucle. Cada vez que se atraviesa el ciclo, el sistema de plantillaprocesará todo entre % for % y % endfor %.

Por ejemplo, podrías utilizar lo siguiente para mostrar una lista de atletas dada la variable athlete_list:

<ul>

Page 41: Django Book Español - Google Drive

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

También 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 patrón común es comprobar el tamaño de una lista antes de recorrer sobre este, y mostrar un textoespecial si está vacía:

% 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 patrón es tan común, la etiqueta for admite la cláusula opcional % empty % quele permite definir que mostrar si la lista está vacía. 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 elvalor de la variable a iterar para que sólo recorra por los valores que deseas iterar. Del mismo modo, nohay soporte para la sentencia “continue” que le instruye al bucle ir inmediatamente al próximo ciclo.(Ver sección “Filosofías y limitciones” más adelante en este capítulo para entender el razonamiento en la

Page 42: Django Book Español - Google Drive

decisión de este diseño.)

Dentro de cada bucle % for %, obtienes acceso a una variable de plantilla llamada forloop. Estavariable contiene varios atributos que le provee información sobre el progreso del bucle:

forloop.counter siempre se establece a un entero representando el número de veces que se haentrado 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 esestablecido al valor 0 la primera vez que recorre el buble.

forloop.revcounter siempre es establecido a un entero representando el número de elementosrestante en el bucle. En el primer ciclo del bucle, forloop.revcounter se establece al número totalde 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. Laprimera vez que entra al bucle, forloop.revcounter0 es establecido al número total de elementosde 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 elbucle. 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 usocomún 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 código de plantilla anterior mostraría algo como lo siguiente:

Link1 | Link2 | Link3 | Link4Otro uso común 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 bucleactual. He aquí un ejemplo:

% for country in countries % <table>

Page 43: Django Book Español - Google Drive

% 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 sólo disponbile dentro de los bucles. Después que el parser de plantilla hayallegado a % endfor %, forloop desaparece.

Contexto y la variable forloopDentro del bloque % for %, las variables existentes son relocalizados para evitar sobrescribir lavariable forloop. Django expone dicho contexto en el objeto forloop.parentloop. Generalmente notienes que preocuparse por esto, pero si provees a la plantilla una variable llamada forloop (aunque ledesaconsejamos su uso), será renombrado forloop.parentloop mientras está dentro del bloque % for%.

ifequal/ifnotequalEl sistema de plantilla de Django, deliberadamente, no es un lenguaje de programación completo y portanto no te permite ejecutar arbitrariamente código python. (Más sobre estas ideas en la sección“Filosofías y limitaciones”.) En todo caso, es bastante común el requisito de comparar dos valores dentrode la plantilla y mostrar algo si son iguales. Django proporciona la etiqueta % ifequal % para estepropósito.

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 código (hard­coded), con comillas simples o dobles, de modo quelo siguiente es válido:

% 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 %.

Page 44: Django Book Español - Google Drive

% ifequal section 'sitenews' % <h1>Site News</h1>% else % <h1>No News Here</h1>% endifequal %

Solamente variables de plantilla, string, enteros y números decimales son permitidos como argumentosa % ifequal %. Estos son ejemplos válidos:

% ifequal variable 1 %% ifequal variable 1.23 %% ifequal variable 'foo' %% ifequal variable "foo" %

Otros tipos de variables, tales como diccionarios, listas o Booleans, no pueden ser hard­coded en %ifequal %. Estos son ejemplos no válidos.

% 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 %.

ComentariosJusto como en HTML o python, el lenguaje de plantilla de Django permite comentarios. Para designar uncomentario, utiliza la etiqueta # #:

# This is a comment #

El comentario no será impreso cuando la plantilla se interpreta. Los comentarios con esta sintaxis nopueden abarcar múltiples líneas. Esta limitación mejora el rendimiento al procesar la plantilla. En lasiguiente plantilla, el resultado se verá exactamente igual como en la plantilla (en otras palabras, laetiqueta de comentario no se procesa como un comentario):

This is a # this is nota comment #test.

Si quieres usar comentarios de múltiples líneas, utiliza la etiqueta % comment % como el ejemplo:

% comment %This is amulti­line comment.% endcomment %

Page 45: Django Book Español - Google Drive

FiltrosComo se explicó al inicio del capítulo, los filtros en la plantilla son formas simples de alterar el valor de lasvariables antes de ser mostrado. Los filtros utilizan el carácter pipe (tubería o barra vertical) de estamanera:

name|lower

El ejemplo muestra el valor de la variable name después de ser filtrada a través del filtro lower, elcual convierte el texto en minúscula. Los filtros también pueden ser encadenados — es decir, pueden serutilizados en conjunto de tal manera que el resultado de un filtro se aplica al siguiente. He aquí unejemplo que toma el primer elemento de una lista y la convierte a mayúsculas.

my_list|first|upper

Algunos filtros pueden tomar argumentos. Un argumento de filtro viene después de dos puntos ysiempre 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 másimportantes. El Apéndice F cubre el resto.

addslashes: agrega backslashes (barra invertida) ante cualquier backslash, comilla simple, ocomilla doble. Esto es útil si, por ejemplo, el texto producido es para incluir en un string deJavaScript.

date: formatea objetos date o datetime de acuerdo a un formato dado en el parámetro. El stringde formato se define en el Apéndice F.

pub_date|date:"F j, Y"

length: devuelve la longitud del valor. Para una lista, este devuelve el número de elementos.Para un string, devuelve el número de caracteres. (Expertos en python, toman nota de que estofunciona en cualquier objeto python que sabe como determinar su longitud — es decir, cualquierobjeto que tenga el método __len__.)

Filosofías y limitacionesAhora que tienes una idea del lenguaje de plantilla en Django, debemos señalar algunas limitacionesintencional, junto con algunas filosofías de por qué funciona de la forma en que funciona.

Más que cualquier otro componente de aplicaciones web, la sintaxis de la plantilla es altamentesubjetivo, y las opiniones entre los programadores varían ampliamente. El hecho de que python por sisolo tiene docenas, si no cientos, de lenguajes de plantillas open source (código abierto), apoyan estepunto. Cada uno fue probablemente creado porque los desarrolladores considera los sistemas deplantillas existentes como inadecuados. (¡De hecho, se dice que es un rito para desarrolladores enpython escribir su propio lenguaje de plantilla! Si aún no lo has hecho, considéralo. Es un ejerciciodivertido.)

Con esto en mente, puede que interese saber que Django no le obliga utilizar su propio sistema de

Page 46: Django Book Español - Google Drive

plantillas. Debido que Django intenta ser un framework completo que proporciona todas las piezasnecesarias para que el desarrollador web sea productivo, muchas veces es más conveniente utilizar elsistema de plantilla de Django que cualquier otra librería de plantillas en python, pero en ningún sentidoes un requisito estricto. Como se verá en la próxima sección, “Utilizando plantillas en las vistas”, es muyfácil utilizar otro lenguaje de plantilla en Django.

Aún así, es claro que tenemos una fuerte preferencia por la forma en que el lenguaje de plantillas deDjango funciona. El sistema de plantilla tiene sus fundamentos en cómo se realiza el desarrollo web enWorld Online más la experiencia combinada de los creadores de Django. Estas son algunas de esasfilosofías:

La lógica del negocio debe ser separado de la lógica de presentación. Los desarrolladores deDjango ven el sistema de plantilla como una herramienta que controla la presentación y la lógicade presentación relacionada a esta — y eso es todo. El sistema de plantilla no debería adherirfuncionalidades que van más allá de este objeto básico.

Por esta razón, es imposible invocar código python directamente dentro de las plantillas deDjango. Toda “programación” esta fundamentalmente limitada al ámbito de lo que puederealizar la etiqueta de plantilla. Es posible escribir etiquetas personalizadas que realice cosasarbitrarias, pero las etiquetas de fábrica en el sistema de plantilla de Django intencionalmenteprohibe la ejecucción arbitraria de código python.

La sintaxis debe ser disociada de HTML/XML. Aunque el sistema de plantilla de Django se utilizaprincipalmente para producir HTML, esta diseñada para que sea utilizable con formatos no HTML,tal como texto plano. Algunos sistemas de plantillas estan basados en XML, ubicando la lógica dela plantilla entre etiquetas y atributos XML, pero Django evita deliberadamente esta limitación.El requisito de generar XML válido al escribir una plantilla introduce un mundo de erroreshumanos que, al analizar los mensajes de error, son de difícil comprensión. El uso de un motorXML para parsear las plantillas incurren en un nivel inaceptable de sobrecarga al procesar laplantilla.

Se asume que los diseñadores están familiarizado con código HTML. El sistema de plantilla noesta diseñado para que las plantillas necesariamente se muestren muy bien en los editoresWYSIWYG como Dreamweaver. Es una limitación muy grave y no permitiría que la sintaxis seatan amigable como es. Django espera que los autores de plantillas se sientan cómodos al editardirectamente HTML.

Se asume que los diseñadores no son programadores en python. Los autores de sistemas deplantillas reconocen que las plantillas para las páginas web son más a menudo escrito pordiseñadores, no programadores, y por lo tanto no debe asumir el conocimiento en python.

Sin embargo, el sistema también intenta acomodar a los equipos pequeños en que las plantillasson creadas por programadores de python. Este ofrece una forma de extender la sintaxis delsistema escribiendo código puro en python. (Más detalles en el capítulo “Plantillas avanzadas”.)

El objetivo no es inventar un lenguaje de programación. El objetivo es ofrecer sólo la suficientefuncionalidad programática, tales como bucles y condicionales, que son esenciales para realizardecisiones en la presentación.

Utilizando plantillas en las vistasHas aprendido los aspectos básicos del uso del sistema de plantilla; ahora utilicemos ese conocimientospara crear una vista. Recordemos la vista current_datetime en mysite.views, que iniciamos en elcapítulo anterior. He aquí el código:

from django.http import HttpResponse

Page 47: Django Book Español - Google Drive

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, podrías pensar hacer algocomo esto:

from django.template import Template, Contextfrom django.http import HttpResponseimport 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 señalan en laintroducción de este capítulo. Es decir, la plantilla está incrustrada en el código python, por lo que laverdadera separación de datos y presentación aún no se logra. Vamos a arreglar eso ubicando la plantillaen un archivo separado, que esta vista cargará.

Podrías considerar guardar la plantilla en algún lugar de tu sistema de archivo y utilizas lasfuncionalidades integradas de python para abrir y leer el contenido de la plantilla. He aquí como podríalucir el código, asumiendo que la plantilla fue almacenada en/home/djangouser/templates/mytemplate.html:

from django.template import Template, Contextfrom django.http import HttpResponseimport 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:

Page 48: Django Book Español - Google Drive

No maneja la situación en que el archivo no se encuentre. Si el archivo mytemplate.html noexiste o no es legible, la invocación a call() levantaría la excepción IOError.

La localización de la plantilla está escrita directamente (hard­coded) en el código. Si fueras autilizar esta técnica para todas las vistas, estarías duplicando la ubicación de la plantilla. ¡Sinolvidar que implica mucha escritura!

Incluye una gran cantidad de código repetitivo aburrido. Tienes cosas mejores que hacer querealizar llamadas a open(), fp.read(), y fp.close() cada vez que cargas una plantilla.

Para resolver estos problemas, vamos a usar las técnicas template loading y template directories.

Cargando plantillaDjango proporciona una potente y conveniente API para cargar plantillas del sistema de archivos, con elobjetivo de eliminar la redundancia tanto al cargar plantillas como en la plantilla en sí misma. Con el finde utilizar esta API, primero necesitarás indicarle a Django dónde están almacenados las plantillas. Ellugar para hacer esto es en el archivo de configuraciones — el archivo settings.py que hemosmencionado en el capítulo anterior, cuando hablamos sobre ROOT_URLCONF. Si estas siguiendo losejercicios, abre el archivo settings.py y localiza la configuración TEMPLATE_DIRS. Por defecto, es unatupla vacía, 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 configuración le indica al mecanismo de la API para cargar plantillas en Django dónde localizar lasplantillas. 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 puedespensar por un lugar apropiado para ubicar las plantillas, le recomendamos crear el directoriotemplates dentro del proyecto — es decir, dentro del directorio mysite que se creó en el capítulo“Iniciando”.¡Si TEMPLATE_DIRS contiene un sólo directorio, no olvides la coma al final del string! La razónde esto es porque python requiere una coma dentro de una tupla de un sólo elemento paraeliminar la ambigüedad con una expresión en paréntesis. Se trata de un error común en losnovatos.

# ¡Mal! Falta la coma al final.TEMPLATE_DIRS = ( '/home/django/mysite/templates')

Page 49: Django Book Español - Google Drive

# Bien. La coma está presente.TEMPLATE_DIRS = ( '/home/django/mysite/templates',)

Si estás en Windows, incluye la letra de la unidad y utiliza la barra diagonal (forward slash) enlugar de la barra diagonal inversa (backslash), como el ejemplo:

TEMPLATE_DIRS = ( 'C:/www/django/templates',)

Lo más simple es utilizar rutas absolutas — es decir, rutas de directorios que comienzan en laraíz del sistema de archivos. Sin embargo, si quieres ser un poco más flexible y desacoplado,puedes tomar ventaja del factor que el archivo de configuración de Django es simplementecódigo python y construir dinámicamente 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 “mágica” __file__ de python, que automaticamente su valor esestablecido al nombre de archivo del módulo en que el código python reside. Este obtiene elnombre del directorio que contiene a settings.py (os.path.dirname), luego lo unifica contemplates de forma multi­plataforma (os.path.join), y finalmente se asegura que se utiliceforward slashes en lugar de backslashes (en caso del sistema Windows).

Mientras estamos en el tema de código python dinámico en el archivo de configuraciones, hayque señalar que es muy importante evitar errores en la configuración. Si introduces un errorsintáctico, o un error en ejecucción (runtime error), es muy probable que el sitio web manejadopor Django colapse.

Una vez ajustado el TEMPLATE_DIRS, el próximo paso es cambiar el código de la vista para que utilice lasfuncionalidades de cargar plantillas de Django en lugar de explicitamente escribir la ruta al código.Volviendo a nuestra vista current_datetime, vamos a cambiarlo:

from django.template.loader import get_templatefrom django.template import Contextfrom django.http import HttpResponseimport datetime

def current_datetime(request): now = datetime.datetime.now() t = get_template('current_datetime.html') html = t.render(Context('current_date': now))

Page 50: Django Book Español - Google Drive

return HttpResponse(html)

En este ejemplo, utilizamos la función django.template.loader.get_template() en lugar manualmentecargar la plantilla desde el sistema de archivos. La función get_template() toma el nombre de la plantillacomo argumento, determina dónde la plantilla reside en el sistema de archivos, abre el archivo, ydevuelve un objeto Template compilado.

En este ejemplo, nuestra plantilla es current_datetime.html, pero no hay nada especial en la extensión.html. Puedes asignarle a la plantilla cualquier extensión que haga más sentido a tu aplicación, o puedesprescindir completamente de la extensión.

Para determinar la localización de la plantilla en el sistema de archivos, get_template() combina eldirectorio de plantilla en TEMPLATE_DIRS con el nombre de la plantilla indicada en get_template(). Porejemplo, si TEMPLATE_DIRS es establecido a “/home/django/mysite/templates”, la invocación aget_template() buscaría la plantilla /home/django/mysite/templates/current_datetime.html.

Si get_template() no puede encontrar la plantilla con el nombre indicado, se levanta una excepciónTemplateDoesNotExist. Para ver como luce, inicia el servidor de desarrollo en Django ejecutando pythonmanage.py runserver dentro del directorio del proyecto Django. Entonces, apunta el navegador hacia lapágina que activa la vista current_datetime (es decir, http://127.0.0.1:8000/time/). Asumiendo que laconfiguración DEBUG está establecida a True y aún no se ha creado la plantilla current_datetime.html,deberías observar una página de error de Django resaltando el error TemplateDoesNotExist.

Figura 4­1: Página de error mostrada cuando la plantilla no puede ser localizada.

Page 51: Django Book Español - Google Drive

Esta página de error es similar a la que explicamos en el capítulo “Vistas y URLconfs”, con una piezaadicional de información depurada: la sección “Template­loader postmortem”. Esta sección le dice cualplantilla Django intentó cargar, junto con el motivo de cada intento fallido — es decir, “File does notexist” (“El archivo no existe”). Esta información es valiosa cuando estás tratando depurar los errores alcargar plantillas.

Continuando, crea el archivo current_datetime.html dentro de tu directorio de plantillas utilizando elsiguiente código:

<html><body>It is now current_date .</body></html>

Recarga la página en tu navegador web, y deberías ver la página completamente procesada.

render_to_response()

We’ve shown you how to load a template, fill a Context and return an HttpResponse object with theresult of the rendered template. We’ve optimized it to use get_template() instead of hard­codingtemplates and template paths. But it still requires a fair amount of typing to do those things. Becausethis is such a common idiom, Django provides a shortcut that lets you load a template, render it andreturn 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, you’ll be using render_to_response() rather than loading templates and creatingContext and HttpResponse objects manually — unless your employer judges your work by total lines ofcode written, that is.Here’s the ongoing current_datetime example rewritten to use render_to_response():

from django.shortcuts import render_to_responseimport datetime

def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', 'current_date':now)

What a difference! Let’s 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 therender_to_response() call. Becauserender_to_response() returns an HttpResponse object, we cansimply 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 don’t provide asecond argument,render_to_response() will use an empty dictionary.

Page 52: Django Book Español - Google Drive

The locals() TrickConsider 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, you’ll find yourself calculating some values, storing them in variables(e.g., now in the preceding code), and sending those variables to the template. Particularly lazyprogrammers should note that it’s slightly redundant to have to give names for temporary variables andgive names for the template variables. Not only is it redundant, but also it’s extra typing.So if you’re one of those lazy programmers and you like keeping code particularly concise, you can takeadvantage of a built­in Python function called locals(). It returns a dictionary mapping all local variablenames to their values, where “local” means all variables that have been defined within the currentscope. 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 function’s execution. As a consequence, we’verenamed the now variable tocurrent_date, because that’s the variable name that the template expects.In this example, locals() doesn’t offer a hugeimprovement, but this technique can save you some typingif you have several template variables to define — or if you’re lazy.One thing to watch out for when using locals() is that it includes every local variable, which maycomprise more variables than you actually want your template to have access to. In the previousexample, locals() will also include request. Whether this matters to you depends on your application andyour 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 templatesin subdirectories of your template directory, and that’s fine. In fact, we recommend doing so; somemore 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 thingwith the first argument to render_to_response(), like this:

return render_to_response('dateapp/current_datetime.html','current_date': now)

There’s no limit to the depth of your subdirectory tree. Feel free to use as many subdirectories as youlike.

Page 53: Django Book Español - Google Drive

NoteWindows users, be sure to use forward slashes rather than backslashes. get_template() assumes aUnix­style file name designation.

The include Template TagNow that we’ve covered the template­loading mechanism, we can introduce a built­in template tag thattakes 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 beeither a variable or a hard­coded (quoted) string, in either single or double quotes. Anytime you havethe 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 andillustrate 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 variabletemplate_name:

% include template_name %

As in get_template(), the file name of the template is determined by adding the template directoryfromTEMPLATE_DIRS to the requested template name.Included templates are evaluated with the context of the template that’s 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 availablein the “included” template, as you would expect.If, in an % include % tag, a template with the given name isn’t found, Django will do one of two

Page 54: Django Book Español - Google Drive

things: If DEBUG is set to True, you’ll 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 InheritanceOur template examples so far have been tiny HTML snippets, but in the real world, you’ll be usingDjango’s template system to create entire HTML pages. This leads to a common Web developmentproblem: across a Web site, how does one reduce the duplication and redundancy of common pageareas, such as sitewide navigation?A classic way of solving this problem is to use server­side includes, directives you can embed within yourHTML 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 isto use a more elegant strategy called template inheritance.In essence, template inheritance lets you build a base “skeleton” template that contains all the commonparts of your site and defines “blocks” that child templates can override.Let’s see an example of this by creating a more complete template for our current_datetime view, byediting 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, thehours_ahead view from Chapter 3? If we want again to make a nice, valid, full HTML template, we’dcreate 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>

Page 55: Django Book Español - Google Drive

<hr> <p>Thanks for visiting my site.</p></body></html>

Clearly, we’ve just duplicated a lot of HTML. Imagine if we had a more typical site, including a navigationbar, a few style sheets, perhaps some JavaScript — we’d end up putting all sorts of redundant HTML intoeach template.The server­side include solution to this problem is to factor out the common bits in both templates andsave them in separate template snippets, which are then included in each template. Perhaps you’d storethe 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 you’d 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. It’s the middle ground that’s messy. Inthis example, both pages feature a title — <h1>My helpful timestamp site</h1> — but that title can’tfit into header.html because the<title> on both pages is different. If we included the <h1> in theheader, we’d have to include the <title>, which wouldn’t allow us to customize it per page. See wherethis is going?Django’s 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 thesnippets that are different.The first step is to define a base template — a skeleton of your page that child templates will later fill in.Here’s 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 %

Page 56: Django Book Español - Google Drive

</body></html>

This template, which we’ll call base.html, defines a simple HTML skeleton document that we’ll use for allthe pages on the site. It’s the job of child templates to override, or add to, or leave alone the contents ofthe blocks. (If you’re following along, save this file to your template directory as base.html.)We’re using a template tag here that you haven’t seen before: the % block % tag. All the % block% tags do is tell the template engine that a child template may override those portions of thetemplate.Now that we have this base template, we can modify our existing current_datetime.html template touse it:

% extends "base.html" %

% block title %The current time% endblock %

% block content %<p>It is now current_date .</p>% endblock %

While we’re at it, let’s create a template for the hours_ahead view from Chapter 3. (If you’re followingalong with code, we’ll leave it up to you to change hours_ahead to use the template system instead ofhard­coded HTML.) Here’s 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 %

Isn’t this beautiful? Each template contains only the code that’s unique to that template. Noredundancy needed. If you need to make a site­wide design change, just make the change tobase.html, and all of the other templates will immediately reflect the change.Here’s 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 theparent template — in this case,base.html.At that point, the template engine notices the three % block % tags in base.html and replaces thoseblocks with the contents of the child template. So, the title we’ve defined in % block title % will beused, as will the% block content %.Note that since the child template doesn’t define the footer block, the template system uses the valuefrom the parent template instead. Content within a % block % tag in a parent template is alwaysused as a fallback.Inheritance doesn’t affect the template context. In other words, any template in the inheritance treewill 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

Page 57: Django Book Español - Google Drive

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 assection­wide navigation.Here are some guidelines for working with template inheritance: If you use % extends % in a template, it must be the first template tag in that template.

Otherwise, template inheritance won’t work. Generally, the more % block % tags in your base templates, the better. Remember, child

templates don’t have to define all parent blocks, so you can fill in reasonable defaults in a number ofblocks, and then define only the ones you need in the child templates. It’s better to have morehooks than fewer hooks.

If you find yourself duplicating code in a number of templates, it probably means you should movethat 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 , whichis a “magic” variable providing the rendered text of the parent template. This is useful if you want toadd 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. Thislimitation exists because a block tag works in “both” directions. That is, a block tag doesn’t justprovide a hole to fill, it also defines the content that fills the hole in the parent. If there were twosimilarly named % block % tags in a template, that template’s parent wouldn’t know which oneof the blocks’ content to use.

The template name you pass to % extends % is loaded using the same method thatget_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 youdon’t know the name of the parent template until runtime. This lets you do some cool, dynamicstuff.

No prestar atención a este bloque, es de uso personal mientras se trabaja el capituloH1 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

Page 58: Django Book Español - Google Drive

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 What’s next?3

H4 About this comment system

#codeiterator = 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);

Capítulo 5: ModelosEn el capítulo 3, cubrimos los conceptos fundamentales de la creación de sitios Web dinámicos conDjango: la creación de vistas y URLconfs. Como explicamos, una vista es responsable de implementaralguna lógica arbitraria, y después devolver una respuesta. En uno de los ejemplos, nuestra lógicaarbitraria fue calcular la fecha y hora actuales.

En aplicaciones Web modernas, la lógica arbitraria a menudo involucra interacción con una base dedatos. Detrás de escena, un sitio Web impulsado por una base de datos se conecta a un servidor de basede datos, recupera algunos datos de esta, y muestra estos datos en una página Web. El sitio tambiénpodría proporcionar funciones a los visitantes del sitio para poblar la base de datos ellos mismos.

Muchos sitios Web complejos proporcionan una combinación de los dos. Amazon.com, por ejemplo, es unbuen caso de un sitio impulsado por una base de datos. Cada página de producto es básicamente es unaconsulta en la base de datos de productos de Amazon formateada como HTML, y cuando envías unareseña, es insertada en la base de datos de las reseñas.

Django es adecuado para crear sitios Web impulsados por bases de datos, ya que incluye herramientaspara realizar consultas a la base de datos de una manera fácil pero poderosa. Este capítulo explica esta

Page 59: Django Book Español - Google Drive

funcionalidad: La capa de base de datos de Django.

Nota: Aunque no es estrictamente necesario conocer teoría básica de bases de datos relacionales y SQLpara usar la capa de base de datos de Django, es muy recomendble. Una introducción a esos conceptosestá fuera del alcance de este libro, pero continúa leyendo si eres nuevo en bases de datos.Probablemente serás capáz de seguir y entender los conceptos en función del contexto.

La manera “Tonta” de hacer consultas a la base de datos en las vistasAsí como en el Capítulo 3 vimos la manera “tonta ” de generar una salida en una vista (hardcodeando eltexto directamente dentro de la vista), hay una manera “tonta” de recuperar datos desde una base dedatos en una vista. Es simple: solo usa una librería existente en Python para ejecutar una consulta SQLy haz algo con los resultados.

En este ejemplo de vista, usamos la librería MySQLdb (disponible enhttp://www.djangoproject.com/r/python­mysql/) para conectarse a una base de datos MySQL, recuperaralgunos registros, y alimentar con ellos un template para mostrar una página Web:

from django.shortcuts import render_to_responseimport 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 vistainmediatamente: Estamos escribiendo directamente en el código los parámetros de la coneccion a la base de datos. Lo

ideal, es poner estos parámetros en el archivo de configuración de nuestro proyecto Django. We’re having to write a fair bit of boilerplate code: creating a connection, creating a cursor,

executing a statement, and closing the connection. Ideally, all we’d have to do is specify whichresults we wanted.

It ties us to MySQL. If, down the road, we switch from MySQL to PostgreSQL, we’ll have to use adifferent 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, thedatabase server we’re using would be abstracted, so that a database server change could be made ina single place. (This feature is particularly relevant if you’re building an open­source Djangoapplication that you want to be used by as many people as possible.)

As you might expect, Django’s database layer aims to solve these problems. Here’s a sneak preview ofhow the previous view can be rewritten using Django’s database API:

django.shortcuts import render_to_responsefrom mysite.books.models import Book

Page 60: Django Book Español - Google Drive

def book_list(request): books = Book.objects.order_by('name') return render_to_response('book_list.html', 'books': books)

Capítulo 6: El sitio admin de DjangoPara cierta clase de sitios web, una interfaz de admin (o interfaz de administración) esparte esencial de la infraestructura. Esta es una interfaz web, limitada a losadministradores del sitio, que permite añadir, editar y borrar contenido del sitio. Algunosejemplos comunes: la interfaz que usas cuando creas una entrada en un blog, el sitio quelos administradores usan para moderar los comentarios, las herramientas que usan tusclientes para actualizar su sitio web que tu les construiste.

Hay un problema con las interfaces de administración: Es aburrido construirlas. Eldesarrollo web es divertido cuando estas desarrollando una funcionalidad que se enfrenta alpúblico, pero construir interfaces de administración es siempre lo mismo. Tienes queautentificar usuarios, desplegar y manejar los formularios, validar la entrada, etc. Esaburrido y repetitivo.

Entonces, ¿Cual es el enfoque de django para este aburrimiento y tareas repetitivas? Elenfoque es que django te provee de todo – en tan solo un par de lineas de código, nomenos. Con django, construir interfaces de administración es un problema resuelto.

Este capítulo es acerca de la interfaz de administración automática de django. Estacaracterística, funciona de la siguiente manera: Lee la metadata en tu modelo para proveeruna lista­para­producción y poderosa interfaz que los administradores de sitios puedenempezar a usar inmediatamente. Aquí, vamos a hablar de como activar, usar y personalizaresta característica.

Nota que nosotros recomendamos que leas este capítulo inclusive si no tienes intensionesde usar el sitio de administración de django, por que aquí introducimos algunos conceptosque aplica para todo django, a pesar del no uso del sitio de administración.