You are on page 1of 106

Tutorial de Django I

HTU UTH

Introduccin a Django
TU UT

Django es un framework de desarrollo web escrito en Python con el que usted puede construir y mantener aplicaciones web de alta calidad con un mnimo de esfuerzo.

Instalar Python
T T

Django est escrito completamente en Python, por lo que el primer paso en la instalacin del marco es el asegurarse de que tiene Python instalado. http://www.python.org/download/
HTU UTH

Instalar Django
T T HTU

http://www.djangoproject.com/download/
UTH

Linux: sudo python setup.py install Windows: python setup.py install Los archivos de Django se instalarn en el directorio site-packages de su instalacin de Python, en donde Python busca las bibliotecas de terceros.

Prueba de la instalacin de Django


T T

En una shell de comandos, cambie a otro directorio (no el directorio que contiene el directorio de Django) e inicie el intrprete de Python interactivo escribiendo python. Si la instalacin fue exitosa, usted debe ser capaz de importar el mdulo de Django: >>> import django >>> django.VERSION (1, 1, 0, final, 1)

Establecer una base de datos


T T

En este punto, usted podra comenzar a escribir una aplicacin Web con Django, porque el nico requisito previo es una instalacin de Python. Sin embargo, es probable que desarrolle un sitio web controlado por base de datos, en cuyo caso tendr que configurar un servidor de base de datos. Django es compatible con cuatro motores de base de datos:

PostgreSQL (http://www.postgresql.org/) SQLite 3 (http://www.sqlite.org/) MySQL (http://www.mysql.com/) Oracle (http://www.oracle.com/)


HTU UTH HTU UTH HTU UTH HTU UTH

La configuracin de la base de datos es un proceso de dos pasos: 1. En primer lugar, tendr que instalar y configurar el servidor de base de datos. 2. En segundo lugar, tendr que instalar la librera Python para nuestra base de datos de back-end. Esto es cdigo Python de terceros que permite interactuar con la base de datos.

Uso de Django con MySQL


T T

Django requiere MySQL 4.0 o superior. Las versiones 3.x no soportan subconsultas anidadas y algunas otras sentencias SQL estndar . Tambin tendr que instalar el paquete de MySQLdb desde http://www.djangoproject.com/r/python-mysql/. En Linux, puede comprobar si su paquete de distribucin del sistema de gestin ofrece un paquete llamado python-mysql, python-MySQLdb, mysql-python, o algo similar.
HTU UTH

Iniciar un proyecto
T T

Una vez que haya instalado Python, Django, y (opcionalmente) el servidor/librera de base de datos, puede dar el primer paso del desarrollo de una aplicacin Django mediante la creacin de un proyecto. Un proyecto es una coleccin de ajustes de una instancia de Django, incluyendo la configuracin de la base de datos, las opciones especficas de Django, y la configuracin de la aplicacin. Si es la primera vez que usa Django, usted tendr que tener cuidado con la configuracin inicial. Cree un nuevo directorio para comenzar a trabajar, tal vez algo como /home/nombre de usuario/djcode/ Vaya al directorio que ha creado y ejecute el comando siguiente: django-admin.py startproject mysite Esto crear un directorio mysite en el directorio actual.
T T

El comando startproject crea un directorio que contiene cuatro archivos: mysite/ __init__.py manage.py settings.py urls.py

__init__.py: Un archivo necesario para que Python trate el directorio mysite como un paquete (un grupo de mdulos de Python). Es un fichero vaco, y normalmente no se le aade nada. manage.py: Utilidad de lnea de comandos que le permite interactuar con el proyecto Django de diversas maneras. Con python manage.py puede tener una idea de lo que puede hacer. Usted nunca tiene que editar este archivo, sino que se crea en el directorio por pura conveniencia. settings.py: Caractersticas de configuracin de este proyecto Django. Echele un vistazo para tener una idea de los tipos de configuraciones disponibles, junto con sus valores predeterminados. urls.py: Las direcciones URL de este proyecto Django. Piense en ello como la tabla de contenidos de su sitio Django. Por el momento, est vaco.

A pesar de su pequeo tamao, estos archivos ya constituyen una aplicacin Django de trabajo.

Ejecutar el servidor de desarrollo (runserver)


T T

El servidor de desarrollo de Django (tambin llamado runserver debido al comando que lanza) es un servidor web ligero que puede utilizar durante el desarrollo de su sitio. Est incluido con Django para que pueda desarrollar su sitio rpidamente, sin tener que lidiar con la configuracin del servidor de produccin (Apache, por ejemplo) hasta que est listo para la produccin. El servidor de desarrollo rastrea su cdigo y automticamente vuelve a cargarlo, por lo que es fcil para usted cambiar el cdigo sin necesidad de reiniciar nada. Para iniciar el servidor, vaya al directorio del proyecto si no lo ha hecho, y ejecute este comando: python manage.py runserver Esto iniciar el servidor de forma local en el puerto 8000, accesible slo para las conexiones de su propio equipo. Ahora que est en ejecucin, visite http://127.0.0.1:8000/ con su navegador Web. Ver un Welcome to Django Funciona!
T T

Tutorial de Django II
HTU UTH

25. febrero 2010 - Visitada 2661 veces, 2 hoy Tcnico


HTU UTH

Vistas y URLconfs
TU UT

Su primera Pgina Django: Hola Mundo


Como primer objetivo, vamos a crear una pgina Web que produzca el mensaje de ejemplo famoso: Hola mundo. Con Django, el contenido de la pgina es producido por una vista, y la direccin se especifica en una URLconf. En primer lugar, vamos a escribir la funcin de la vista Hola Mundo. Una vista Hola Mundo es simple. Aqu est toda la funcin que debe escribir en el archivo views.py:
T T

from django.http import HttpResponse def hello(request): return HttpResponse(Hello world) Una vista en Python es slo una funcin que toma un HttpRequest como su primer parmetro y devuelve una instancia de HttpResponse. Para que una funcin de Python sea una vista Django, tiene que hacer esas dos cosas. (Hay excepciones, pero las veremos ms tarde.) Si en este momento ejecuta python manage.py runserver de nuevo, seguirs viendo el mensaje Bienvenido a Django, sin ningn rastro de Hola mundo. Eso se debe a que el proyecto mysite no conoce la vista hello; se necesita ahora decirle a Django explcitamente que se va a activar esa vista en una determinada URL, usando URLconf. Un URLconf es como una tabla de contenidos para un sitio web Django. Bsicamente, es un mapeo entre las URL y las funciones de vista que deben llamarse para esas direcciones URL. El URLconf por defecto incluye algunas caractersticas comentadas de uso comn en Django, por lo que la activacin de esas caractersticas es tan fcil como descomentar las lneas adecuadas. Si se ignora el cdigo comentado, aqu est la esencia de un URLconf:
T T T T T T

from django.conf.urls.defaults import * urlpatterns = patterns(, )

Lo ms importante a destacar es la variable urlpatterns, que Django espera encontrarla en el mdulo URLconf. Esta variable define la asignacin entre las direcciones URL y el cdigo que controla las direcciones URL. Por defecto, el URLconf est vaco la aplicacin Django est en blanco. Para agregar una URL y una vista al URLconf, simplemente aadir una tupla Python que asigna un patrn de URL a la funcin de la vista. He aqu cmo conectarlo en la vista hello: from django.conf.urls.defaults import * from mysite.views import hello urlpatterns = patterns(, (^hello/$, hello), ) En pocas palabras, se le dice a Django que cualquier peticin a la URL /hello/ debera ser gestionada por la funcin de vista hello. Para probar los cambios a la URLconf, inicie el servidor de desarrollo de Django con el comando python manage.py runserver. (Si usted lo dej ejecutndose tambin est bien. El servidor de desarrollo detecta automticamente los cambios en su cdigo Python y vuelve a cargarlos cuando sea necesario, para que no tenga que reiniciar el servidor entre los cambios.) El servidor se est ejecutando en la direccin http://127.0.0.1:8000/, por lo que abra un navegador Web y vaya a http://127.0.0.1:8000/hello/. Usted debe ver el texto Hola mundo, la salida de su vista Django. Usted hizo su primera pgina web en Django.

Una nota rpida sobre errores 404


En este punto, el URLconf define slo un nico patrn de URL: el que trata las solicitudes de la direccin /hello/. Qu sucede cuando usted solicita una direccin URL diferente? Usted debe ver un mensaje de Pgina no encontrada. Django muestra este mensaje porque ha solicitado una URL que no est definida en su URLconf. La utilidad de esta pgina va ms all del mensaje bsico de error 404. Tambin le dice, de forma precisa que URLconf Django es usada y cada patrn utilizado en el URLconf. De esa informacin, usted debe ser capaz de determinar por qu la direccin URL solicitada arroj un error 404. Naturalmente, esta informacin es confidencial y est destinada nicamente a usted, el desarrollador Web. Si esto fuese un sitio de desplegado en Internet, usted no deseara exponer esa informacin al pblico. Por esta razn, esta pgina Pgina no encontrada, se muestra slo si su Proyecto de Django se encuentra en modo de depuracin. Le explicaremos cmo desactivar el modo de depuracin ms tarde. Por ahora, slo sepa que cada proyecto Django creado se encuentra en modo de depuracin, y si el proyecto no est en modo de depuracin, Django emite una respuesta 404 diferente.

Una nota rpida sobre la raz del sitio


Como se explic en la ltima seccin, ver un mensaje de error 404 si usted va a la raz del sitio: http://127.0.0.1:8000/. El patrn URL para que coincida con la raz del sitio es un poco contradictorio, por lo que es digno de mencin. Cuando est listo para poner en prctica una vista de la raz del sitio, utilice el patrn de URL ^$, que coincide con una cadena vaca. He aqu un ejemplo: from mysite.views import hello, my_homepage_view urlpatterns = patterns(, (^$, my_homepage_view), # ) Cmo Django procesa una peticin: 1. Una peticin viene a /hello/. 2. Django determina el URLconf raz en base a ROOT_URLCONF. 3. Django busca en todos los urlpatterns del URLconf por el primero que coincida con /hello/. 4. Si encuentra una coincidencia, llama a la funcin de vista asociada. 5. La funcin de vista devuelve un HttpResponse. 6. Django convierte el HttpResponse en la respuesta HTTP apropiada, que resulta en una pgina web. Ahora que conoce los aspectos bsicos de cmo hacer pginas Django. Es muy sencillo, en realidad: slo escribir funciones de vista y mapearlas a URLs a travs de URLconfs.

Segunda vista: contenido dinmico


Vamos a crear algo ms dinmico: una pgina Web que muestre la fecha y hora actuales. Este es un paso agradable y simple, porque no se trata de una base de datos o cualquier entrada de usuario, slo la salida del reloj interno del servidor. Es slo un poco ms emocionante que Hola mundo, pero se muestran un par de conceptos nuevos. Para realizar una vista Django que muestre la fecha y hora actuales, slo es necesario colocar la sentencia datetime.datetime.now() en una vista y devolver un HttpResponse.
T T

from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now()

html = It is now %s. % now return HttpResponse(html) Al igual que con la funcin de vista hello, esta debe residir en views.py. Este es el aspecto completo de views.py:
T T T T

from django.http import HttpResponse import datetime def hello(request): return HttpResponse(Hello world) def current_datetime(request): now = datetime.datetime.now() html = It is now %s. % now return HttpResponse(html) Despus de aadir esto a views.py, agreguar el patrn URL a urls.py para decirle a Django que URL debe manejar esta vista. Algo como /time/ tendra sentido:
T T

from django.conf.urls.defaults import * from mysite.views import hello, current_datetime urlpatterns = patterns(, (^hello/$, hello), (^time/$, current_datetime), ) Con la vista escrita y la URLconf actualizada, arrancar el runserver y visitar http://127.0.0.1:8000/time/ en el navegador. Usted debera ver la fecha y hora actuales.

URLconfs y acoplamiento dbil


Ahora es un buen momento para destacar una filosofa clave detrs de URLconfs y detrs de Django en general: el principio de acoplamiento dbil. Si dos trozos de cdigo estn dbilmente acoplados, los cambios realizados a uno de ellos tendr poco o ningn efecto en el otro. Las URLconfs de Django son un buen ejemplo de este principio en la prctica. En una aplicacin Web Django, las definiciones de URL y las funciones de vista que ellas

llaman estn dbilmente acopladas, es decir, la decisin de lo que la URL debe ser para una determinada funcin y la implementacin de la funcin residen en dos lugares diferentes. Esto le permite intercambiar una pieza sin afectar a la otra. Por ejemplo, considere la vista del current_datetime. Si usted quiere cambiar la direccin por ejemplo, para moverla de /time/ a /current-time/ podra hacer un cambio rpido en URLconf sin tener que preocuparse por la vista. Del mismo modo, si usted quisiera cambiar la funcin de vista que altera la lgica de alguna manera, podra hacerlo sin afectar a la URL a la que est vinculada la funcin. Adems, si usted quiere exponer a la actual funcionalidad de la fecha en varias URL, usted fcilmente podra hacerlo editando URLconf, sin tener que tocar el cdigo de la vista. En este ejemplo, el current_datetime est disponible en dos URLs. Es un ejemplo artificial, pero esta tcnica puede ser til: urlpatterns = patterns(, (^hello/$, hello), (^time/$, current_datetime), (^another-time-page/$, current_datetime), ) Las URLconfs y las vistas estn dbilmente acopladas en la accin.

Tercera vista: URLs dinmicas


En la vista current_datetime, el contenido de la pgina, la fecha/hora actual, es dinmica, pero la direccin (/time/) es esttica. En la mayora de aplicaciones Web dinmicas, sin embargo, una direccin URL contiene los parmetros que influyen en la salida de la pgina. Por ejemplo, una librera on-line podra dar a cada libro su propia URL. Crearemos una tercera vista que muestre la fecha y hora actuales compensada por un cierto nmero de horas. El objetivo es disear un sitio para que la pgina /time/plus/1/ muestre la fecha y hora dentro de una hora, la pgina /time/plus/2/ muestra la fecha y hora dentro de dos horas, la pgina /time/plus/3/ muestre la fecha y hora dentrop de tres horas, y as sucesivamente. Un principiante podra pensar en codificar una funcin de vista distinta para cada desplazamiento de hora, que podra dar lugar a una URLconf como: 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), ) Entonces, cmo disear la aplicacin para manejar los desplazamiento de hora arbitrarios? La clave es usar comodines de patrones URL. Como se mencion anteriormente, un patrn URL es una expresin regular, por lo que puede utilizar el patrn de expresin regular \d+ para que coincida con uno o ms dgitos: urlpatterns = patterns(, # (r^time/plus/\d+/$, hours_ahead), # ) Este nuevo patrn URL casar con cualquier URL como /time/plus/2/, /time/plus/25/, o incluso /time/plus/100000000000/. Ahora, vamos a limitarlo de forma que se permita un desplazamiento mximo de 99 horas. Esto significa que queremos permitir, nmeros de uno o de dos dgitos, y en la sintaxis de la expresin regular, que se traduce en \d(1,2): (r^time/plus/\d{1,2}/$, hours_ahead), Un detalle importante que se introduce aqu es el carcter r al principio de la expresin regular. Este caracter le dice a Python que la cadena es una raw string su contenido no debe interpretar barras invertidas. En las cadenas normales de Python, las barras invertidas son usadas para caracteres de escape especiales, como la cadena \n, que es una cadena de caracteres que contiene una nueva lnea. Cuando se agrega el r para que sea una raw string, Python, no aplica el escape de la barra invertida, por lo que r\n es una cadena de dos caracteres que contiene una barra invertida literal y la n minscula. Se recomienda fuertemente que utilice raw string en cualquier momento si est definiendo una expresin regular en Python. A partir de ahora, todos los urlpatterns en este libro sern raw string. Ahora que se ha designado un comodn para la direccin, usted necesita una manera de pasar esos datos de comodn a la funcin de vista, de modo que usted pueda utilizar una funcin de vista nica para cualquier desplazamiento de hora arbitrario. Usted puede hacer esto colocando entre parntesis los datos de la URLpattern que desea guardar. En el caso del ejemplo, lo que desea guardar es cualquier nmero que se introduzca en la URL, as que ponga parntesis alrededor de \d(1,2), de esta manera: (r^time/plus/(\d{1,2})/$, hours_ahead),

Usted est utilizando parntesis para capturar datos del texto concordante. El URLconf final, incluidos los ltimos dos puntos de vista, se parece a esto: from django.conf.urls.defaults import * from mysite.views import hello, current_datetime, hours_ahead urlpatterns = patterns(, (r^hello/$, hello), (r^time/$, current_datetime), (r^time/plus/(\d{1,2})/$, hours_ahead), ) hours_ahead es muy similar a la vista current_datetime escrita antes, con una diferencia clave: que lleva un argumento extra que el nmero de horas de desplazamiento. Aqu est la vista de cdigo: from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = In %s hour(s), it will be %s. % (offset, dt) return HttpResponse(html) Con esta funcin de vista y el URLconf escrito, iniciar el servidor de desarrollo de Django (si no est ya en ejecucin), y visitar http://127.0.0.1:8000/time/plus/3/ para verificar que funciona. A continuacin, intentar http://127.0.0.1:8000/time/plus/5/. Luego http://127.0.0.1:8000/time/plus/24/. Por ltimo, visitar http://127.0.0.1:8000/time/plus/100/ para comprobar que el patrn en el URLconf acepta nmeros slo de uno o dos dgitos; Django debera mostrar un error de Pgina no encontrada en este caso, tal y como vimos. La URL http://127.0.0.1:8000/time/plus/ (sin horas) tambin debera lanzar un error 404.

Pginas de error bonitas en Python


Vamos a introducir deliberadamente un error de Python comentando en el archivo views.py las lneas offset=int(offset) en la vista de hours_ahead: def hours_ahead(request, offset): # try: # offset = int(offset) # except ValueError: # raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = In %s hour(s), it will be %s. % (offset, dt) return HttpResponse(html) Inicie el servidor de desarrollo y vaya a /time/plus/3/. Usted ver una pgina de error con mucha informacin, incluido un mensaje TypeError que aparece en la parte superior: unsupported type for timedelta hours component: unicode Qu pas? Pues bien, la funcin de datetime.timedelta espera que el parmetro de horas que se le pase sea un nmero entero, y el trozo de cdigo que convierte el desplazamiento a un nmero entero fue comentado. Eso provoca que datetime.timedelta lance un TypeError. Es el tpico pequeo fallo que todos los programadores han cometido en algn momento. El objetivo de este ejemplo es mostrar las pginas de error de Django. Tmese su tiempo para explorar la pgina de error y conocer la distinta informacin que ofrece. La pgina de error de Django es capaz de mostrar ms informacin en ciertos casos especiales, como el caso de errores de sintaxis de plantilla. Los veremos ms tarde, cuando hablemos del sistema de plantillas de Django. Por el momento, descomente las lneas del offset = int (offset) para obtener la funcin de vista funcionando correctamente de nuevo.

Tutorial de Django III


HTU UTH

29. marzo 2010 - Visitada 1660 veces, 2 hoy Tcnico


HTU UTH

Plantillas Templates
TU UT

No es una buena idea codificar el HTML directamente en las vistas. Es mucho ms limpio y ms fcil de mantener separar el diseo de la pgina del cdigo Python. Podemos hacer esto con el sistema de plantillas de Django.
T T

Base del Sistema de Plantillas


Una plantilla de Django es una cadena de texto para separar la presentacin de un documento de sus datos. Una plantilla define contenedores y varios bits de lgica bsica (etiquetas) que regulan la forma en que el documento debe ser mostrado. Por lo general las plantillas se utilizan para producir HTML, pero las plantillas Django plantillas son igualmente capaces de generar cualquier otro formato basado en texto. Comencemos con una plantilla sencilla de ejemplo. Esta plantilla Django describe una pgina HTML que, da las gracias a una persona por hacer un pedido a la empresa. <html> <head><title>Ordering notice</title></head> <body> <h1>Ordering notice</h1> <p>Dear {{ person_name }},</p> Thanks for placing an order from {{ company }}. Its scheduled to ship on {{ ship_date|date:F j, Y }}. Here are the items youve ordered: <ul> {% for item in item_list %} <li>{{ item }}</li> {% endfor %} </ul> {% if ordered_warranty %} Your warranty information will be included in the packaging. {% else %}

You didnt order a warranty, so youre on your own when the products inevitably stop working. {% endif %} Sincerely, {{ company }} Esta plantilla es HTML bsico con algunas variables y etiquetas de plantilla dentro de ella. Cualquier texto rodeado por un par de llaves (por ejemplo, {{ person_name }}) es una variable. Esto significa insertar el valor de la variable con el nombre dado. Cmo podemos especificar los valores de las variables?Llegaremos a eso despus. Cualquier texto que est rodeado de llaves y porcentaje (por ejemplo, {% if ordered_warranted %}) es una etiqueta de plantilla. La definicin de una etiqueta es bastante amplia: una etiqueta slo le dice al sistema de plantillas haz algo. Por ltimo, el segundo prrafo de esta plantilla contiene un ejemplo de filtro, que es la forma ms conveniente de modificar el formato de una variable. En este ejemplo, {{ ship_date | date: F j, Y }}, estamos pasandole a la variable ship_date el filtro date, dndole al filtro date el argumento F j, Y. El formato de filtro date formatea las fechas a un formato dado, como se especifica en el argumento. Los filtros son adjuntados con un carcter de canalizacin (|). Cada plantilla Django tiene acceso a varias etiquetas y filtros incorporados, muchos de los cuales sern discutidos en las siguientes secciones.

Usando el sistema de plantillas


Entremos en el sistema de plantillas de Django para que cmo funciona, pero no estamos todava para integrarlo con las vistas que hemos creado en el captulo anterior. Nuestro objetivo aqu es mostrar cmo funciona el sistema independiente del resto de Django. (Por lo general vamos a usar el sistema de plantillas dentro de una vista de Django, pero hay que dejar claro que el sistema de plantillas es slo una librera de Python que se puede utilizar en cualquier lugar, no slo en las vistas de Django.)
T T

Esta es la forma ms bsica en que se puede utilizar el sistema de plantillas de Django: 1. Crear un objeto Template proporcionando el cdigo de la plantilla raw como una cadena. 2. Llamar al mtodo render () del objeto Template con un conjunto de variables (el contexto). Esto devuelve una plantilla renderizada completamente como una cadena, con todas las variables y etiquetas de plantilla evaluadas de acuerdo al contexto. >>> 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.

Crear objetos Template


La forma ms fcil de crear un objeto Template es crear una instancia directamente. La clase Template reside en el mdulo django.template, y el constructor toma un argumento, el cdigo de plantilla raw.
T T T T

Veamos algunos aspectos bsicos del sistema de plantillas: >>> from django.template import Template >>> t = Template(My name is {{ name }}.) >>> print t Si lo estamos haciendo de forma interactiva, veremos algo como esto: <django.template.Template object at 0xb7d5f24c> Cuando se crea un objeto Template, el sistema de plantillas compila el cdigo de la plantilla raw internamente de forma optimizada, preparndolo para el renderizado. Pero si el cdigo de la plantilla incluye cualquier error de sintaxis, la llamada a Template() producir una excepcin TemplateSyntaxError.
T T

Renderizar un Template
Una vez que tiene un objeto Template, puede pasarle datos, dndole un contexto. Un contexto es simplemente un conjunto de nombres de variables de plantilla y sus valores asociados. Una plantilla usa un contexto para rellenar sus variables y evaluar sus etiquetas. Un contexto es representado en Django por la clase Context, que reside en el mdulo django.template. Su constructor toma un argumento opcional: un diccionario que mapea los nombres de variables a los valores de las variables. Llamar al mtodo render() del objeto Template con el contexto para rellenar la plantilla:
T T

>>> from django.template import Context, Template >>> t = Template(My name is {{ name }}.) >>> c = Context({name: Stephane}) >>> t.render(c) uMy name is Stephane. Debemos sealar aqu que el valor de retorno de t.render(c) es un objeto Unicode no una cadena Python normal. Django utiliza objetos Unicode en lugar de cadenas normales en todo el framework. He aqu un ejemplo de compilar y renderizar una plantilla, usando una plantilla similar a la ejemplo del principio de este captulo:

>>> from django.template import Template, Context >>> raw_template = " Dear {{ person_name }}, <p>Thanks for placing an order from {{ company }}. Its 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 didnt order a warranty, so youre on your own when the products inevitably stop working.</p> {% endif %} <p>Sincerely, <br/>{{ company }} <p> " >>> t = Template(raw_template) >>> import datetime >>> c = Context({person_name: John Smith, company: Outdoor Equipment, ship_date: datetime.date(2009, 4, 2), ordered_warranty: False}) >>> t.render(c) u <p>Dear John Smith,</p>\n\n<p>Thanks for placing an order from Outdoor Equipment. Its scheduled to\nship on April 2, 2009.</p>\n\n\n<p>You didnt order a warranty, so youre on your own when\nthe products inevitably stop working.</p>\n\n\n<p>Sincerely,Outdoor Equipment</p> 1. Primero importamos las clases Template y Context, ambas residen en el mdulo django.template. 2. Guardamos el texto raw de nuestra plantilla en la variable raw_template. Tenga en cuenta que usamos comillas triples para designar a la cadena, ya que se extiende por varias lneas, por contra, las cadenas entre comillas sencillas no pueden ser envueltas en varias lneas. 3. A continuacin creamos un objeto plantilla, t, pasando raw_template al constructor de la clase Template. 4. Importamos el mdulo de fecha y hora de la librera estndar de Python, porque la necesitaremos en la siguiente declaracin. 5. Creamos un objeto Context, c. El constructor de Context, toma un diccionario Python, que mapea los nombres de variable a los valores. Aqu, por ejemplo, se especifica que persona_name es John Smith, company es Outdoor Equipment , y as sucesivamente. 6. Por ltimo, llamamos al mtodo render () de nuestro objeto plantilla, pasndole el contexto. Esto devuelve la plantilla renderizada, es decir, que reemplaza las variables de la plantilla con los valores actuales de las variables, y ejecuta cualquier etiqueta de la plantilla.

Esos son los fundamentos del uso del sistema de plantillas de Django: simplemente escribir una cadena de plantilla, crear un objeto Template, crear un Context, y llamar al mtodo render().
T T

Mltiples contextos, misma plantilla


Una vez que tiene un objeto Template, usted puede renderizar mltiples contextos a travs de l. Considere este ejemplo: >>> from django.template import Template, Context >>> t = Template(Hello, {{ name }}) >>> print t.render(Context({name: John})) Hello, John >>> print t.render(Context({name: Julie})) Hello, Julie >>> print t.render(Context({name: Pat})) Hello, Pat Cada vez que usted est utilizando la misma plantilla para renderizar mltiples contextos, es ms eficiente crear el objeto plantilla una vez, y luego llamar a render() sobre l varias veces: # Bad for name in (John, Julie, Pat): t = Template(Hello, {{ name }}) print t.render(Context({name: name})) # Good t = Template(Hello, {{ name }}) for name in (John, Julie, Pat): print t.render(Context({name: name}))

Bsqueda de variable de Contexto


En los ejemplos hasta ahora, hemos pasado valores simples a los contextos en su mayora cadenas, adems de un datetime.date. Sin embargo, el sistema de plantillas maneja estructuras de datos complejas, tales como listas, diccionarios, y objetos personalizados.
T T

La clave para atravesar estructuras complejas de datos en las plantillas Django es el carcter de punto (.). Utilice un punto para acceder a las claves del diccionario, atributos, mtodos, o ndices de un objeto.
T T

Por ejemplo, supongamos que usted est pasando un diccionario Python a una plantilla. Para acceder a los valores de ese diccionario por clave de diccionario, use el punto: >>> from django.template import Template, Context >>> person = {name: Sally, age: 43} >>> t = Template({{ person.name }} is {{ person.age }} years old.)

>>> c = Context({person: person}) >>> t.render(c) uSally is 43 years old. Del mismo modo, los puntos tambin permiten el acceso a los atributos de los objetos. Por ejemplo, un objeto datetime.date de Python tiene atributos ao, mes, da, y puede utilizar un punto para acceder a esos atributos en una plantilla Django: >>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template(The month is {{ date.month }} and the year is {{ date.year }}.) >>> c = Context({date: d}) >>> t.render(c) uThe month is 5 and the year is 1993. Este ejemplo utiliza una clase personalizada, lo que demuestra que los puntos permiten tambin el acceso a atributos de objetos arbitrarios: >>> from django.template import Template, Context >>> class Person(object): def __init__(self, first_name, last_name): self.first_name, self.last_name = first_name, last_name >>> t = Template(Hello, {{ person.first_name }} {{ person.last_name }}.) >>> c = Context({person: Person(John, Smith)}) >>> t.render(c) uHello, John Smith. Los puntos tambin puede hacer referencia a mtodos de objetos. Por ejemplo, cada cadena Python tiene los mtodos upper() y isdigit(), y usted puede llamarlos en las plantillas Django, usando la misma sintaxis del punto: >>> from django.template import Template, Context >>> t = Template({{ var }}{{ var.upper }}{{ var.isdigit }}) >>> t.render(Context({var: hello})) uhelloHELLOFalse >>> t.render(Context({var: 123})) u123123True

Tenga en cuenta que no se incluyen los parntesis en las llamadas a mtodos. Adems, no es posible pasar argumentos a los mtodos, slo puede llamar a mtodos que no requieren argumentos. Por ltimo, los puntos tambin se utilizan para acceder a los ndices de lista, como en este ejemplo: >>> from django.template import Template, Context >>> t = Template(Item 2 is {{ items.2 }}.) >>> c = Context({items: ['apples', 'bananas', 'carrots']}) >>> t.render(c) uItem 2 is carrots. Las bsquedas de puntos se pueden resumir as: cuando la plantilla se encuentra con un punto en un nombre de variable, trata las bsquedas siguientes, en este orden:

Diccionario (por ejemplo, foo["bar"]) Atributo (por ejemplo, foo.bar) Llamada a mtodo (por ejemplo, foo.bar()) ndice de Lista (por ejemplo, foo[2])

El sistema utiliza el tipo de bsqueda que funciona primero. Es una falta de lgica del circuito. Las bsquedas del punto se pueden anidar varios niveles de profundidad. Por ejemplo, el ejemplo siguiente utiliza {{ person.name.upper() }}, que se traduce en una bsqueda de diccionario (person['name']) y luego una llamada al mtodo (upper()): >>> from django.template import Template, Context >>> person = {name: Sally, age: 43} >>> t = Template({{ person.name.upper }} is {{ person.age }} years old.) >>> c = Context({person: person}) >>> t.render(c) uSALLY is 43 years old.

Comportamiento de llamada a mtodo


Las llamadas a los mtodos son un poco ms complejas que el de otros tipos de bsqueda. Aqu hay algunas cosas a tener en cuenta. Si, durante la bsqueda de mtodos, un mtodo produce una excepcin, la excepcin se propagar a menos que la excepcin tenga un atributo silent_variable_failure a True. Si la excepcin tiene un atributo silent_variable_failure, la variable se renderizar como una cadena vaca, como en este 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})) uMy name is . Una llamada al mtodo slo funcionar si el mtodo no requiere argumentos. De lo contrario, el el sistema se mover al siguiente tipo de bsqueda (ndice de lista). Obviamente, algunos mtodos tienen efectos colaterales y sera absurdo, y, posiblemente, incluso un agujero de seguridad, permitir al sistema de plantillas acceder a ellos. Digamos, por ejemplo, que tiene un objeto BackAccount que tiene un mtodo delete(). Si una plantilla incluye algo como {{ account.delete() }}, donde account es un objeto BankAccount, el objeto sera eliminado al procesar la plantilla. Para evitar esto, establezca el atributo de funcin alters_data en el mtodo: def delete(self): # Delete the account delete.alters_data = True El sistema de plantillas no ejecutar cualquier mtodo marcado de esta manera. Continuando con el ejemplo actual, si una plantilla incluye {{ account.delete }} y el mtodo delete() tienen alters_data = True, entonces el mtodo delete() no se ejecutar cuando la plantilla se renderice. En su lugar, se producir un error silencioso.

Cmo se gestionan las variables invlidas?


Por defecto, si una variable no existe el sistema de plantillas la renderiza como una cadena vaca, error silencioso. Considere este ejemplo:

>>> from django.template import Template, Context >>> t = Template(Your name is {{ name }}.) >>> t.render(Context()) uYour name is . >>> t.render(Context({var: hello})) uYour name is . >>> t.render(Context({NAME: hello})) uYour name is . >>> t.render(Context({Name: hello})) uYour name is .

Jugar con objetos Context


La mayora de las veces, usted instanciar objetos Context pasando un diccionario totalmente lleno a Context(). Pero usted tambin puede aadir y eliminar elementos de un objeto Context, una vez instanciado,usando la sintaxis estndar de Python diccionario:
T T

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

Etiquetas y Filtros de Plantilla Bsica


Etiquetas
T T T

if / else
T

La etiqueta {% if %} evala una variable, y si esa variable es True (es decir, que existe, no est vaco, y no es un valor boolean FALSE), el sistema mostrar todo entre {% if %} y {% endif %}, como en este ejemplo: {% if today_is_weekend %} Welcome to the weekend! {% endif %} Una etiqueta {% else %} es opcional: {% if today_is_weekend %}

Welcome to the weekend! {% else %} Get back to work. {% endif %} for


T T

La etiqueta {% for %} permite un bucle sobre cada elemento de una secuencia. La plantilla renderizar todo entre {% for %} y {% endfor %}. Por ejemplo, podra utilizar el siguiente ejemplo para mostrar una lista de atletas dada una variable athlete_list: <ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul> y al revs: {% for athlete in athlete_list reversed %} {% endfor %} Es posible anidar etiquetas {% for %}. La etiqueta for soporta una clausula opcional {% empty %} que le permite definir que salida si la lista est vaca. {% for athlete in athlete_list %} {{ athlete.name }} {% empty %} There are no athletes. Only computer programmers. {% endfor %} No hay soporte para opciones del tipo break y continue. Dentro de cada bucle {% for %} usted puede acceder a una variable llamada forloop. Esta variable tiene algunas caractersticas que le dan informacin sobre el progreso del bucle:

forloop.counter siempre se establece en un nmero entero que representa el nmero de veces que se ha entrado en el bucle. forloop.counter0 es como forloop.counter, excepto que es indexado en cero. Su valor ser fijado a 0 la primera vez que se entre en el bucle. forloop.revcounter siempre se establece en un nmero entero que representa el nmero de elementos restantes del bucle. forloop.revcounter0 es como forloop.revcounter, excepto que es indexado en cero. forloop.first es un valor booleano que se establece a True si esta es la primera iteracin del bucle. forloop.last es un valor booleano que se establece a True si esta es la ltima iteracin del bucle. forloop.parentloop es una referencia al objeto forloop del bucle padre, en caso de bucles anidados.
T

ifequal / ifnotequal
T

La etiqueta {% ifequal %} compara dos valores y muestra todo entre {% ifequal %} y {% endifequal %} si los valores son iguales. Este ejemplo compara la plantilla de las variables user y currentuser: {% ifequal user currentuser %} <h1>Welcome!</h1> {% endifequal %} Al igual que {% if %} la etiqueta {% ifequal %} soporta un {% else %} opcional: {% ifequal section sitenews %} <h1>Site News</h1> {% else %} <h1>No News Here</h1> {% endifequal %} Slo las variables de plantilla, cadenas, enteros y nmeros decimales se permiten como argumentos para {% ifequal %}. Estos son ejemplos vlidos: {% ifequal variable 1 %} {% ifequal variable 1.23 %} {% ifequal variable foo %} {% ifequal variable foo %} Cualquier otro tipo de variables, tales como diccionarios, listas o booleanos no pueden codificarse en la etiqueta {% ifequal %}. Estos son ejemplos invlidos:

{% ifequal variable True %} {% ifequal variable [1, 2, 3] %} {% ifequal variable {key: value} %} Si necesita testear si algo es verdadero o falso, use {% if %} en lugar de {% ifequal %}. Comentarios
T T

Para designar un comentario usar {# #}. No pueden usar esta sintaxis para varias lneas. Para ello usar la etiqueta {% comment %}, como esto: {% comment %} This is a multiline comment. {% endcomment %} Filtros
T T

Los filtros de plantilla son formas sencillas de alterar el valor de las variables antes de renderizarlas. Los filtros utilizan un carcter de canalizacin (pipe), como esto: {{ name|lower }} Los filtros se pueden encadenar, es decir, que pueden ser usados en conjunto de manera que la salida de un filtro se aplica al siguiente. He aqu un ejemplo que convierte el primer elemento de una lista a maysculas: {{ my_list|first|upper }} Algunos filtros toman argumentos que vienen despus de dos puntos y siempre entre comillas dobles. He aqu un ejemplo: {{ bio|truncatewords:30 }} Esto muestra las primeras 30 palabras de la variable bio. Los siguientes son algunos de los filtros ms importantes:

addslashes: Agrega una barra invertida antes de que cualquier barra invertida, comillas simples o comillas dobles. Esto es til si el texto producido se incluye en una cadena JavaScript. date: Formatea una cadena de fecha o fecha/hora de acuerdo a un formato dado como parmetro. length: Devuelve la longitud del valor. Para una lista, devuelve el nmero de elementos. Para una cadena, devuelve el nmero de caracteres. Funciona en cualquier objeto Python que sabe cmo determinar su propia longitud, es decir, cualquier objeto que tiene un mtodo __len__()

Filosofas y limitaciones
Ahora que usted tiene una idea del sistema de plantillas de Django, hay que sealar alguna de sus limitaciones intencionales, junto con algo de filosofa de por qu funciona de la forma en que funciona. Ms que cualquier otro componente de las aplicaciones web, la sintaxis de las plantillas es muy subjetiva, y las opiniones de los programadores varan significativamente. Con esto en mente, es posible que le interese saber que Django no requiere que usted use su lenguaje de plantillas. Debido a que Django est destinado a ser un completo entorno web que proporcione todas las piezas necesarias para los desarrolladores web para ser productivo, muchas veces es ms conveniente el uso del sistema de plantillas de Django que otras libreras de plantillas Python, pero no es un requisito estricto en ningn sentido. Sin embargo, est claro que tenemos una fuerte preferencia por el lenguaje de plantillas de Django. El sistema de plantillas tiene sus races en la forma en que el desarrollo web se hace en el mundo en lnea combinado con la experiencia de los creadores de Django. Aqu estn algunas de nuestras filosofas:

La lgica de negocio deben estar separada de la lgica de presentacin. Los desarrolladores de Django ven el sistema de plantillas como una herramienta que controla la presentacin y la lgica relacionada con la presentacin, y eso es todo. La sintaxis debe estar desacoplada del HTML/XML. Aunque el sistema de plantillas de Django se utiliza principalmente para producir HTML, su intencin es ser tan til para los formatos no HTML, tales como el texto sin formato. Los diseadores se supone que se sienten cmodos con el cdigo HTML. El sistema de plantillas no est diseado de manera que las plantillas necesariamente se muestran muy bien en los editores WYSIWYG como Dreamweaver. Django espera que los autores de plantillas estn cmodos editando el HTML directamente. Se asume que los diseadores no son programadores de Python. Los autores del sistema de plantillas reconocen que a menudo las plantillas de las pginas web son escritas por los diseadores, no por programadores, y por lo tanto no se debe asumir el conocimiento de Python. El objetivo no es inventar un lenguaje de programacin. El objetivo es ofrecer como mucho la funcionalidad del esquema de programacin, tal como la ramificacin y la iteracin, que es esencial para la toma de decisiones relacionadas con la presentacin.

Usando plantillas en vistas


Recordemos la vista current_datetime en mysite.views. Esto es:
T T

from django.http import HttpResponse import datetime def current_datetime(request):

now = datetime.datetime.now() html = It is now %s. % now return HttpResponse(html) Vamos a cambiar esta vista para utilizar el sistema de plantillas de Django. Al principio se podra pensar en hacer algo como esto: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = Template(It is now {{ current_date }}.) html = t.render(Context({current_date: now})) return HttpResponse(html) Est claro que utiliza el sistema de plantillas, pero no resuelve los problemas que hemos sealado. A saber, la plantilla est incrustada en el cdigo Python, por lo que no se logra una verdadera separacin de los datos y la presentacin. Vamos a arreglar esto poniendo la plantilla en un archivo separado, que cargar esta vista. En primer lugar, podra considerar la posibilidad de guardar la plantilla en algn lugar de su sistema de ficheros y usar Python para leer el contenido de la plantilla. Esto es lo que podra parecerse, suponiendo que la plantilla se ha guardado en el archivo /home/djangouser/templates/mytemplate.html: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() # Simple way of using templates from the filesystem. # This is BAD because it doesnt 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) Este enfoque, sin embargo, es poco elegante, por estas razones:

No maneja el caso de que el archivo falle, como se seala en el cdigo. Si el archivo mytemplate.html no existe o no es legible, la llamada open() lanzar una excepcin IOError. Codifica a pelo la ubicacin de la plantilla. Si usted fuera a utilizar esta tcnica para cada funcin de vista, estara duplicando las localizaciones de la plantilla por no mencionar que se trata de escribir mucho. Incluye una gran cantidad de cdigo repetitivo aburrido. Tienes cosas mejores que hacer que escribir las llamadas a open(), fp.read(), y fp.close() cada vez que se carga una plantilla.
T

Para resolver estos problemas, vamos a utilizar la carga de plantillas y la herencia de plantillas.
T

Carga de Plantillas
Django proporciona un API cmodo y eficaz para la carga de plantillas del sistema de archivos, con el objetivo de eliminar la redundancia, tanto en las llamadas de carga de plantillas como en las plantillas en s mismas. Para usar esta API de carga de plantillas, primero tendr que decirle al marco donde se almacenan las plantillas. El lugar para hacerlo es su archivo de configuracin settings.py que hemos mencionado en el captulo anterior, cuando se introdujo la propiedad ROOT_URLCONF.
T T

Abra settings.py y encuentre la propiedad TEMPLATE_DIRS. De forma predeterminada, es una tupla vaca, y es probable que contenga 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. # Dont forget to use absolute paths, not relative paths. ) Este ajuste le indica al mecanismo de carga de plantillas de Django donde buscar las plantillas. Elija un directorio donde desea almacenar sus plantillas y aadalo a TEMPLATE_DIRS, as:

TEMPLATE_DIRS = ( /home/django/mysite/templates, ) Hay algunas cosas que debe recordar:

Usted puede especificar cualquier directorio que desee, siempre y cuando el directorio y las plantillas dentro de ese directorio sean legibles por la cuenta de usuario en las que el servidor Web se ejecuta. Se recomienda la creacin de un directorio de plantillas dentro de su proyecto (es decir, dentro del directorio que ha creado mysite) Si su TEMPLATE_DIRS slo contiene un directorio, no se olvide de la coma al final de la cadena del directorio. Python requiere comas dentro de tuplas de un solo elemento para eliminar la ambigedad de la tupla de una expresin en parntesis. Si est en Windows, incluya la letra de la unidad y utilice las barra inclinadas al estilo Unix en lugar de las barras invertidas.

Lo ms simple es utilizar rutas absolutas (es decir, rutas de directorios que comienzan en la raz del sistema de archivos). Si quiere ser un poco ms flexible, sin embargo, usted puede construir TEMPLATE_DIRS dinmicamente, como en este ejemplo: import os.path TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), templates).replace(\\,'/), ) Este ejemplo utiliza la variable mgica de Python __file__, que se ajusta automticamente al nombre de archivo del mdulo de Python en que reside el cdigo. Se pone el nombre del directorio que contiene a settings.py (os.path.dirname), y se une con las plantillas de una manera (os.path.join), y entonces asegura que todo lo que se utiliza sean barras inclinadas en lugar de barras invertidas (en el caso de Windows). Con TEMPLATE_DIRS activo, el siguiente paso es cambiar el cdigo para el uso de la funcionalidad de la carga de plantillas de Django en lugar de codificar a pelo las rutas de las plantillas. Volviendo a nuestra vista current_datetime, vamos a cambiarla de esta manera: from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import datetime

def current_datetime(request): now = datetime.datetime.now() t = get_template(current_datetime.html) html = t.render(Context({current_date: now})) return HttpResponse(html) La funcin get_template() toma un nombre de plantilla como argumento, busca dnde la plantilla residee en el sistema de archivos, abre ese archivo, y devuelve un objeto Template compilado. Si get_template() no puede encontrar la plantilla con el nombre que se le da, lanza una excepcin TemplateDoesNotExist.
T T

Ahora, crear el archivo current_datetime.html dentro de su directorio de plantillas mediante el siguiente cdigo de plantilla: It is now {{ current_date }}. Actualice la pgina en el explorador Web, y usted debera ver la pgina completamente renderizada.

render_to_response()
Hemos mostrado cmo cargar una plantilla, rellenar un contexto, y devolver un objeto HttpResponse con el resultado de la plantilla renderizada. Lo hemos optimizado mediante el uso de get_template() en lugar de la codificacin a pelo de las plantillas y las rutas de plantillas. Sin embargo, todava se requiere una buena cantidad de cdigo para escribir todas esas cosas. Debido a que estos pasos son iguales, Django proporciona una abreviatura que le permite cargar una plantilla, renderizarla, y devolver un HttpResponse, todo en una sola lnea de cdigo.
T T

Esta abreviatura es una funcin llamada render_to_response(), que reside en el mdulo django.shortcuts. Aqu est el ejemplo current_datetime reescrito para utilizar render_to_response():
T T

from django.shortcuts import render_to_response import datetime def current_datetime(request): now = datetime.datetime.now() return render_to_response(current_datetime.html, {current_date: now}) El primer argumento de render_to_response() es el nombre de la plantilla a usar. El segundo argumento, si lo hay, debe ser un diccionario para usar en la creacin de un

contexto para la plantilla. Si usted no proporciona un segundo argumento, render_to_response() utiliza un diccionario vaco.

locals()
Muchas veces, usted se encontrar que usted mismo clcula algunos valores, los almacena en variables (por ejemplo, now en el cdigo anterior), y enva esas variables a la plantilla. Esto es un poco redundante y tambin significa escribir ms.
T T

Usted puede usar la funcin Python llamada locals(). Esta devuelve un diccionario que asigna todos los nombres de variables locales a sus valores, donde local significa todas las variables que han sido definidas en el mbito local. As, la vista anterior podra reescribirse as:
T T T T

def current_datetime(request): current_date = datetime.datetime.now() return render_to_response(current_datetime.html, locals()) Hemos cambiado el nombre de la variable a current_date ahora, ya que ese es el nombre de variable que la plantilla espera.

Subdirectorios en get_template()
Puede ser difcil de manejar el almacenar todas sus plantillas en un solo directorio. Usted podra almacenar plantillas en subdirectorios de su directorio de plantillas, y eso est bien. De hecho, le recomendamos hacerlo; algunas caractersticas ms avanzadas de Django (como el sistema de vistas genricas) esperan esta disposicin de plantillas por defecto. t = get_template(dateapp/current_datetime.html) Ya que render_to_response() es una pequea envoltura alrededor de get_template(), usted puede hacer lo mismo con el primer argumento de render_to_response(), as: return render_to_response(dateapp/current_datetime.html, {current_date: now})

La etiqueta de plantilla include


Podemos introducir una etiqueta de plantilla integrada: {% include%}. Esta etiqueta permite incluir el contenido de otra plantilla. El argumento de la etiqueta debe ser el nombre de la plantilla a incluir, y el nombre de la plantilla puede ser una variable o una cadena entre comillas simples o dobles. Cada vez que tenga el mismo cdigo en varias plantillas, considere el uso de {% include %} para eliminar la redundancia. Estos dos ejemplos incluyen el contenido de la plantilla nav.html. Los ejemplos son equivalentes e ilustran bien el uso de las comillas simples o dobles:

{% include nav.html %} {% include nav.html %} El siguiente ejemplo incluye el contenido de la plantilla, cuyo nombre figura en la variable template_name: {% include template_name %} Al igual que en get_template(), el nombre del fichero de la plantilla se determina mediante la adicin al directorio de plantillas de TEMPLATE_DIRS para el nombre de la plantilla. La plantillas incluidas son evaluadas dentro del contexto de la plantilla que las incluye. Por ejemplo, considere estas dos plantillas: # mypage.html {% include includes/nav.html %} <h1>{{ title }}</h1> # includes/nav.html <div id=nav>You are in: {{ current_section }}</div> Si renderiza mypage.html con un contexto que contiene current_section, entonces la variable estar disponible en la plantilla incluida, como era de esperar. Si, en una etiqueta {% include %}, no se encuentra una plantilla con el nombre dado, Django har una de estas 2 cosas:

Si DEBUG es True, ver una excepcin TemplateDoesNotExist en una pgina de error de Django. Si DEBUG es False, la etiqueta fallar de forma silenciosa, no visualizando nada en el lugar de la etiqueta.

Herencia de plantillas
Nuestros ejemplos de plantillas hasta ahora han sido pequeos fragmentos de cdigo HTML, pero en el mundo real usted utilizar el sistema de plantillas de Django para crear pginas enteras de HTML. Esto lleva a un problema de desarrollo web comn: a travs de un sitio Web, cmo se puede reducir la duplicacin y la redundancia de reas de pgina comunes, tales como la navegacin de todo el sitio? Una forma clsica de resolver este problema es usar includes de lado servidor, las directivas que usted puede incrustar dentro de sus pginas HTML para incluir una pgina web dentro de otra. De hecho, Django soporta esta aproximacin con la etiqueta {% include %} que acabamos de describir. Pero la forma preferida de resolver este problema con Django es utilizar una estrategia ms elegante llamado herencia de plantillas.

En esencia, la herencia de plantillas le permite construir una plantilla esqueleto base que contiene todas las partes comunes de su sitio y define bloques que las plantillas hijas puede rellenar.
T T

Veamos un ejemplo de esto creando una plantilla ms completa para nuestra vista current_datetime, editando el archivo current_datetime.html:
T T

<!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> It is now {{ current_date }}. <hr>Thanks for visiting my site. </body> </html> Eso se ve muy bien, pero qu sucede cuando queremos crear una plantilla para otra vista por ejemplo, la vista hours_ahead? Si queremos volver a hacer otra plantilla HTML agradable, vlida, completa, nos quedar algo como esto: <!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> In {{ hour_offset }} hour(s), it will be {{ next_time }}. <hr>Thanks for visiting my site. </body> </html> Es evidente que hay mucho HTML duplicado. Imagnese si tuviramos un sitio ms tpico, incluyendo una barra de navegacin, una hojas de estilo, tal vez algo de JavaScript empezaremos metiendo todo ese HTML redundante en cada plantilla.

La solucin de include de lado servidor a este problema es factorizar las partes comunes de ambas plantillas y guardarlos en distintos fragmentos de plantilla, que luego son incluidos en cada plantilla. Tal vez desee guardar la parte superior de la plantilla en un archivo llamado header.html:
T T

<!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.01//EN> <html lang=en> <head> y quiz almacenar la parte inferior en un fichero llamado footer.html:
T T

<hr> <p>Thanks for visiting my site.</p> </body> </html> Con una estrategia basada en include, los encabezados y los pies de pgina son fciles. Es el punto medio el desordenado. En este ejemplo, ambas pginas tienen un ttulo -<h1>My helpful timestamp site </h1> pero ese ttulo no puede encajar en header.html porque el <title> en ambas pginas es diferente. Si incluimos el <h1> en la cabecera, tendramos que incluir el <title>, que no nos permitira personalizarlo por pgina. El sistema de herencia de plantillas de Django soluciona estos problemas. Puede pensar en ello como una versin dentro-fuera de los includes de lado servidor. En lugar de definir los fragmentos de cdigo que son comunes, se definen los fragmentos de cdigo que son diferentes. El primer paso es definir una plantilla base, un esqueleto de la pgina que las plantillas hijas rellenarn despus. Aqu hay una plantilla base para nuestro ejemplo en curso: <!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.01//EN> <html lang=en> <head> <title>{% block title %}{% endblock %}</title> </head> <body> <h1>My helpful timestamp site</h1> {% block content %}{% endblock %} {% block footer %} <hr>

<p>Thanks for visiting my site.</p> {% endblock %} </body> </html> Esta plantilla, que llamaremos base.html, define un documento de esqueleto HTML sencillo que se utilizar para todas las pginas del sitio. Es el trabajo de las plantillas hijas reemplazar, aadir o dejar vaco el contenido de los bloques.
T T

Estamos utilizando una etiqueta de plantilla que no hemos visto antes: la etiqueta {% block %}. Todo lo que hace una etiqueta {% block %} es decirle al motor de plantillas que una plantilla hija puede sustituir aquellas partes de la plantilla. Ahora que tenemos esta plantilla base, podemos modificar nuestra plantilla current_datetime.html existente:
T T

{% extends base.html %} {% block title %}The current time{% endblock %} {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %} Vamos a crear una plantilla para la vista hours_ahead del Captulo 3. Se podra parecer a esto:
T T

{% extends base.html %} {% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %} No es esto bonito? Cada plantilla contiene slo el cdigo que es nico para esa plantilla. No hay redundancia. Si usted necesita hacer un cambio de diseo de todo el sitio, slo haga el cambio a base.html, y todas las otras plantillas inmediatamente reflejarn el cambio.
T T

He aqu cmo funciona. Cuando se carga la plantilla current_datetime.html, el motor de plantillas ve la etiqueta {% extends %}, notando que esa plantilla es una plantilla hija. El motor carga inmediatamente la plantilla padre en este caso, base.html.
T T T T

En ese momento, el motor de plantillas nota las tres etiquetas {% block %} de base.html y sustituye esos bloques con el contenido de la plantilla hija. La herencia no afecta al contexto de la plantilla. En otras palabras, cualquier plantilla en el rbol de herencia tendr acceso a cada una de sus variables de plantilla en el contexto. Puede utilizar tantos niveles de herencia, segn sea necesario. Una forma comn de utilizar la herencia es el siguiente enfoque de tres niveles: 1. Crear una plantilla base.html que contenga el diseo principal de su sitio. Esta contiene las cosas que rara vez o nunca se cambian. 2. Crear una plantilla base_SECTION.html por cada seccin del sitio (por ejemplo, base_photos.html y base_forum.html). Estas plantillas extienden a base.html e incluyen estilos y diseo especficos de la seccin. 3. Crear plantillas individuales para cada tipo de pgina, como una pgina del foro o una galera de fotos. Estas plantillas extienden a la plantilla de la seccin correspondiente. Este mtodo maximiza la reutilizacin de cdigo y facilita el aadir elementos a las zonas comunes, como la seccin de navegacin. Aqu hay algunas pautas para trabajar con herencia de plantillas:

Si usted usa {% extends %} en una plantilla, debe ser la primera etiqueta de esa plantilla. Generalmente, cuanto ms etiquetas {% block %} en sus plantillas base, mejor. Recordar que las plantillas hijas no tienen que definir todos los bloques de los padres, as que usted puede definir en las plantillas hijas slo los que necesita. Si usted encuentra duplicacin de cdigo en varias plantillas, probablemente significa que usted debe mover el cdigo a una etiqueta {% block %} de una plantilla padre. Si usted necesita obtener el contenido del bloque de la plantilla padre, use {{ block.super }}, que es una variable mgica que proporciona el texto renderizado de la plantilla padre. Esto es til si desea aadir el contenido de un bloque padre en lugar de sobreescribirlo completamente. Usted no puede definir mltiples etiquetas {% block %} con el mismo nombre en la misma plantilla. Esta limitacin existe porque una etiqueta de bloque funciona en ambas direcciones. Es decir, un etiqueta de bloque no slo proporcionan un contenedor para rellenar, sino que tambin define el contenido que rellena el contenedor en el padre. Si hubiese dos etiquetas {% block %} llamadas iguales en una plantilla, el padre no sabra cual de los contenidos de bloque utilizar. El nombre de plantilla que se pasa a {% extends %} se carga utilizando el mismo mtodo que usa get_template(). Es decir, el nombre de la plantilla se aade a la propiedad TEMPLATE_DIRS. En la mayora de los casos, el argumento de {% extends %} ser una cadena, pero puede ser una variable, si usted no sabe el nombre de la plantilla padre hasta tiempo de ejecucin. Esto le permite hacer algunas cosas de forma dinmica.

Tutorial de Django IV
HTU UTH

9. abril 2010 - Visitada 1839 veces, 1 hoy Tcnico


HTU UTH

Modelos
TU UT

Hemos visto los fundamentos de la construccin de sitios Web dinmicos con Django: la configuracin de vistas y URLconfs. Como hemos explicado, una vista es responsable de hacer alguna lgica arbitraria, y luego devolver una respuesta. En uno de los ejemplos, nuestra lgica arbitraria fue calcular la fecha y hora actuales. En las modernas aplicaciones Web, la lgica arbitraria implica a menudo interactar con una base de datos. Un sitio web controlado por base de datos se conecta a un servidor de base de datos, recupera algunos de los datos, y muestra esos datos en una pgina Web. El sitio tambin puede proporcionar medios para que los visitantes rellenen la base de datos por su cuenta. Django es muy adecuado para hacer sitios web controlados por base de datos porque viene con poderosas herramientas para la realizacin de consultas de base de datos usando Python. Este captulo explica esta funcionalidad: la capa de base de datos de Django.
T T

La forma Tonta de hacer consultas de base de datos en Vistas


Hay una manera tonta de recuperar datos de una base de datos en una vista. Es muy sencillo: slo tiene que utilizar cualquier librera de Python existente para ejecutar una consulta SQL y hacer algo que con los resultados. En esta vista de ejemplo, usamos la librera MySQLdb para conectarse a una base de datos MySQL, recuperar algunos registros, y pasarlos a una plantilla para mostrar como una pgina Web: from django.shortcuts import render_to_response import MySQLdb def book_list(request): db = MySQLdb.connect(user=me, db=mydb, passwd=secret, host=localhost) cursor = db.cursor() cursor.execute(SELECT name FROM books ORDER BY name)

names = [row[0] for row in cursor.fetchall()] db.close() return render_to_response(book_list.html, {names: names}) Este enfoque funciona, pero algunos problemas saltan a la vista de inmediato:

Estamos codificando a pelo los parmetros de conexin a la base de datos. Idealmente, esos parmetros deberan almacenarse en la configuracin de Django. Estamos escribiendo una gran cantidad de cdigo redundante: la creacin de una conexin, la creacin de un cursor, la ejecucin de una sentencia, y el cierre de la conexin. Idealmente, todo lo que tendramos que hacer es especificar que resultados queremos. Esto est ligado a MySQL. Si, cambiamos de MySQL a PostgreSQL, vamos a tener que utilizar un adaptador de base de datos diferente, modificar los parmetros de la conexin, y dependiendo de la naturaleza de la instruccin SQL, posiblemente reescribir el cdigo SQL. Idealmente, el servidor de base de datos que estamos utilizando debera abstraerse, de modo que un cambio de servidor de base de datos podra hacerse en un solo lugar. (Esta caracterstica es especialmente til si usted est construyendo una aplicacin Django de fuente abierta que usted desea que sea usada por tanta gente como sea posible.)

Como es de esperar, la capa de base de datos de Django tiene por objeto resolver estos problemas. He aqu una vista previa de cmo la vista anterior se puede reescribir utilizando la API de base de datos de Django:
T T

from django.shortcuts import render_to_response from mysite.books.models import Book def book_list(request): books = Book.objects.order_by(name) return render_to_response(book_list.html, {books: books})

El patrn de desarrollo MTV (o MVC)


Antes de profundizar ms en el cdigo, vamos a considerar el diseo general de una aplicacin web Django controlada por base de datos. En las funciones de vista, por ejemplo, hablamos de la importancia de separar la lgica de negocio de la lgica de presentacin mediante el uso de un sistema de plantillas. Con la capa de base de datos, aplicaremos la misma filosofa para la lgica de acceso a datos. Estas tres piezas juntas lgica de acceso a datos, lgica de negocio, y la lgica de presentacin constituyen un concepto que a menudo se denomina patrn de arquitectura de software Modelo-Vista-Controlador (MVC). En este patrn, Modelo hace referencia a la capa de acceso a datos, Vista hace referencia a la parte del sistema que selecciona qu mostrar y cmo mostrarlo, y controlador hace referencia a la parte del sistema que decide qu vista usar, en funcin de la entrada del usuario, accediendo al modelo cuando sea necesario.
T T

Django sigue este patrn MVC lo suficientemente cerca que puede ser denominado un marco MVC. As es ms o menos cmo M, V, y C se descomponen en Django:

M, la parte de acceso a datos, est a cargo de la capa de base de datos de Django, que se describe en este captulo. V, la parte que selecciona los datos para mostrar y cmo mostrarlo, es manejado por las vistas y las plantillas. C, la parte que delega a una vista en funcin de la entrada del usuario, es manejado por el marco en s, siguiendo su URLconf y llamando a la funcin de Python adecuada para la direccin dada.

Debido a que la C es manejada por el propio marco y la mayor parte de la emocin en Django se produce en los modelos, plantillas, y vistas, Django ha sido denominado como un marco MTV. En el patrn de desarrollo MTV:

M significa modelo, la capa de acceso a datos. Esta capa todo lo relacionado con los datos: cmo acceder a ellos, cmo validarse, las relaciones entre los datos. T representa Plantilla, la capa de presentacin. Esta capa contiene las decisiones relacionadas con la presentacin. V significa Vista, la capa de lgica de negocio. Esta capa contiene la lgica que accede al modelo ylo remite a la plantilla adecuada(s). Usted puede verlo como el puente entre los modelos y plantillas.

Configuracin de la base de datos


En primer lugar, tenemos que realizar alguna configuracin inicial, debemos decirle a Django qu servidor de base de datos utilizar y cmo conectarse a l. Al igual que TEMPLATE_DIRS, la configuracin de la base de datos reside en el archivo de configuracin de Django, llamado settings.py por defecto. Editar el archivo y buscar la configuracin de base de datos.
T T

Una vez que haya introducido esa configuracin y guarde settings.py, es bueno comprobar su configuracin. Para ello, ejecute python manage.py shell, dentro del directorio del proyecto mysite.
T T T T T T

>>> from django.db import connection >>> cursor = connection.cursor() Si no ocurre nada, entonces la base de datos est configurada correctamente. De lo contrario, comprobar el mensaje de error en busca de pistas acerca de lo que est fallando.

Su primera aplicacin
Ahora que ha verificado que la conexin funciona, es hora de crear una aplicacin Django, un paquete de cdigo Django, que incluya modelos y vistas, que residan juntos en un paquete Python nico y que representan una aplicacin Django completa.

Ya creamos un proyecto en el captulo 2, cul es la diferencia entre un proyecto y una aplicacin?


Un proyecto es una instancia de un determinado conjunto de aplicaciones Django, ms la configuracin de esas aplicaciones. Tcnicamente, el nico requisito de un proyecto es que suministra un archivo de configuracin, que define la informacin de conexin de bases de datos, la lista de aplicaciones instaladas, el TEMPLATE_DIRS, y as sucesivamente. Una aplicacin es un conjunto porttil de funcionalidad Django, que generalmente incluye modelos y vistas, que residen juntos en un paquete nico Python. Por ejemplo, Django viene con una serie de aplicaciones, tales como un sistema de comentarios y una interfaz de administracin automtica. Un aspecto clave sobre estas aplicaciones es que son portables y reutilizables a travs de mltiples proyectos.

Si usted est utilizando la capa de base de datos de Django (modelos), debe crear una aplicacin Django. Los modelos deben residir dentro de aplicaciones. As que, para empezar a escribir nuestros modelos, tendremos que crear una aplicacin nueva. En el directorio del proyecto mysite, escriba este comando para crear una aplicacin books:
T T T T T

python manage.py startapp books Este comando no produce ningn resultado, pero s crea un directorio books en el directorio mysite.
T T T T

books/ __init__.py models.py tests.py views.py Esto es el estado en blanco de su aplicacin Django.

Definir modelos en Python


Un modelo de Django es una descripcin de los datos en su base de datos, representada como cdigo Python. Es su disposicin de los datos el equivalente de sus sentencias SQL CREATE TABLE, excepto que es en Python en lugar de SQL, y que incluye algo ms que definiciones de columna de base de datos. Django usa un modelo para ejecutar cdigo SQL y devolver estructuras de datos Python que representan las filas de las tablas de base de datos. Django tambin utiliza modelos para representar conceptos de alto nivel que SQL no necesariamente puede manejar. Si usted est familiarizado con bases de datos, su primer pensamiento podra ser: No es redundante la definicin de modelos de datos en Python en lugar de en SQL? Django funciona de manera que lo hace por varias razones:
T T

A fin de proporcionar una API de acceso a datos conveniente, Django necesita saber el diseo de la bases de datos de alguna manera, y hay dos maneras de lograr esto. La primera es describir explcitamente los datos en Python, y la segunda es la introspeccin en la base de datos en tiempo de ejecucin para determinar los modelos de datos. Esta segunda va parece ms limpia, ya que los metadatos residen slo en un lugar, pero introduce algunos problemas. En primer lugar, la introspeccin de una base de datos en tiempo de ejecucin requiere sobrecarga. Si el marco ha de realizar la introspeccin cada vez que se procesa una solicitud, incurre en un nivel inaceptable de sobrecarga. En segundo lugar, algunas bases de datos no guardan los suficientes metadatos para una introspeccin precisa y completa. Escribir en Python es divertido, y mantener todo en Python limita el nmero de veces que su cerebro tiene que hacer un cambio de contexto lo que ayuda a la productividad. Contar con modelos de datos almacenados como cdigo en lugar de en su base de datos hace que sea ms fcil de mantener sus modelos bajo control de versiones. De esta manera, usted puede fcilmente hacer un seguimiento de los cambios en sus diseos de datos. SQL permite nicamente un grado determinado de metadatos acerca de un diseo de datos. La mayora de los sistemas de base de datos, por ejemplo, no ofrecen un tipo de datos especializado para la representacin de direcciones de e-mail o URL. Los modelos de Django lo hacen. SQL es inconsistente a travs de plataformas de base de datos. Si est distribuyendo una aplicacin Web, por ejemplo, es mucho mejor distribuir un mdulo Python que describa su diseo de datos que conjuntos distintos de sentencias CREATE TABLE para MySQL, PostgreSQL, y SQLite.

Su primer modelo
Nos centraremos en un diseo de datos basado en libro/autor/editor. Usaremos esto como ejemplo, porque las relaciones conceptuales entre libros, autores y editores son bien conocidas. Vamos a suponer los siguientes conceptos, campos, y relaciones:

El autor tiene un nombre, un apellido y una direccin de correo electrnico. Un editor tiene un nombre, una direccin, ciudad, estado o provincia, un pas, y un sitio web. Un libro tiene un ttulo y una fecha de publicacin. Tambin tiene uno o ms autores (relacin de muchos a muchos con autores) y un solo editor (relacin uno a muchos clave ajena con los editores).

El primer paso del uso de este diseo de base de datos con Django es expresarlo como cdigo Python. En models.py, el archivo que fue creado por el comando startapp, escriba lo siguiente:
T T

from django.db import models class Publisher(models.Model):

name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() La primera cosa a notar es que cada modelo est representado por una clase Python que es una subclase de django.db.models.Model. La clase padre, Model, contiene toda la maquinaria necesaria para hacer que estos objetos sean capaces de interactuar con una base de datos. Lo crea o no, esto es todo el cdigo que tiene que escribir para tener acceso bsico a los datos con Django.
T T

Cada modelo corresponde generalmente a una tabla de base de datos nica, y cada atributo del modelo generalmente corresponde a una columna de esa tabla de base de datos. El nombre del atributo corresponde al nombre de la columna, y el tipo de campo (por ejemplo, CharField) corresponde al tipo de la columna de base de datos (por ejemplo, varchar). Django puede generar el comando CREATE TABLE automticamente, como mostraremos despus. La excepcin a la regla de una clase por cada tabla de base de datos es el caso de las relaciones muchos-a-muchos. En nuestro modelo de ejemplo, el libro tiene un campo ManyToMany llamado autores. Esto designa que un libro tiene uno o varios autores, pero la tabla de base de datos Libros no tiene una columna de autores. En lugar de ello, Django crea una tabla adicional, una tabla de referencias cruzadas de muchos-a-muchos , que se encarga del mapeo de los libros a los autores.
T T

Por ltimo, tenga en cuenta que no hemos definido explcitamente una clave primaria en ninguno de estos modelos. A menos que usted lo indique, Django automticamente le da a cada modelo una clave primaria de entero autonumrico llamado id. Cada modelo de Django necesita tener una clave primaria de una sola columna.
T T

Instalar el modelo

Ahora vamos a crear las tablas en nuestra base de datos. Con el fin de hacer eso, el primer paso es activar estos modelos en nuestro proyecto Django. Lo hacemos mediante la adicin de la aplicacin books a la lista de aplicaciones instaladas en el archivo de configuracin.
T T T T

Edite el archivo settings.py de nuevo, y busque la propiedad INSTALLED_APPS, que le dice a Django que aplicaciones estn activas para un proyecto determinado. De forma predeterminada, se ve algo como esto:
T T

INSTALLED_APPS = ( django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.sites, ) Temporalmente comentemos las cuatro lneas poniendo una almohadilla (#) al principio de ellos. Comentenmos tambin la propiedad por defecto MIDDLEWARE_CLASSES. A continuacin, aadir: mysite.books a la lista INSTALLED_APPS, por lo que la propiedad finalmente podra parecerse a esto:
T T

MIDDLEWARE_CLASSES = ( # django.middleware.common.CommonMiddleware, # django.contrib.sessions.middleware.SessionMiddleware, # django.contrib.auth.middleware.AuthenticationMiddleware, ) INSTALLED_APPS = ( # django.contrib.auth, # django.contrib.contenttypes, # django.contrib.sessions, # django.contrib.sites, mysite.books, ) Ahora que la aplicacin Django se ha activado en el archivo de configuracin, podemos crear las tablas de base de datos en nuestra base de datos. En primer lugar, vamos a validar los modelos con la ejecucin de este comando:
T T

python manage.py validate Si sus modelos son vlidos, ejecute el comando siguiente para que Django genere las declaraciones CREATE TABLE de los modelos de la aplicacin books:

python manage.py sqlall books El comando sqlall en realidad no crea las tablas en su base de datos slo imprime en pantalla la salida para que pueda ver el SQL que Django ejecutara. Si quisiera, podra copiar y pegar este SQL en su cliente de base de datos. Sin embargo, Django proporciona una manera ms fcil de llevar a cabo las sentencias SQL en la base de datos: el comando syncdb:
T T T T

python manage.py syncdb Ejecutando ese comando ver algo como esto: Creating table books_publisher Creating table books_author Creating table books_book Installing index for books.Book model El comando syncdb es una simple sincronizacin de sus modelos a su base de datos. Busca en todos los modelos de cada aplicacin en su propiedad INSTALLED_APPS, comprueba la base de datos para ver si las tablas apropiadas existen ya, y crea las tablas si no existen an. Tenga en cuenta que syncdb no sincroniza los cambios en los modelos o las eliminaciones de los modelos; si usted hace un cambio a un modelo o elimina un modelo, y desea actualizar la base de datos, syncdb no gestionar eso.
T T T T T T

Acceso bsico a datos


Una vez que ha creado un modelo, Django proporciona automticamente una API de alto nivel Python para trabajar con esos modelos. Prubelo mediante la ejecucin de python manage.py shell y escribiendo lo siguiente:
T T

>>> from books.models import Publisher >>> p1 = Publisher(name=Apress, address=2855 Telegraph Avenue, city=Berkeley, state_province=CA, country=U.S.A., website=http://www.apress.com/) >>> p1.save() >>> p2 = Publisher(name=OReilly, address=10 Fawcett St., city=Cambridge, state_province=MA, country=U.S.A., website=http://www.oreilly.com/) >>> p2.save() >>> publisher_list = Publisher.objects.all() >>> publisher_list [<Publisher: Publisher object>, <Publisher: Publisher object>] Cuando crea objetos utilizando la API de modelos de Django, Django no guarda los objetos en la base de datos hasta que llama al mtodo save():
T T

p1 = Publisher() # At this point, p1 is not saved to the database yet! p1.save() # Now it is.

Si desea crear un objeto y guardarlo en la base de datos en un solo paso, use el mtodo objects.create(). Este ejemplo es equivalente al anterior:
T T

>>> p1 = Publisher.objects.create(name=Apress, address=2855 Telegraph Avenue, city=Berkeley, state_province=CA, country=U.S.A., website=http://www.apress.com/) >>> p2 = Publisher.objects.create(name=OReilly, address=10 Fawcett St., city=Cambridge, state_province=MA, country=U.S.A., website=http://www.oreilly.com/) >>> publisher_list = Publisher.objects.all() >>> publisher_list

Aadir representaciones de cadena del Modelo


Cuando mostramos la lista de editores, todo lo que obtuvimos en pantalla fue una vista intil que hace difcil distinguir los objetos Publisher: [<Publisher: Publisher object>, <Publisher: Publisher object>] Podemos solucionar este problema fcilmente mediante la adicin de un mtodo llamado __unicode__() a nuestra clase Publisher. Un mtodo __unicode__() le dice a Python cmo mostrar la representacin Unicode de un objeto.
T T T T

Puede ver esto en accin aadiendo un __unicode__() para los tres modelos: from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() def __unicode__(self): return self.name class Author(models.Model): first_name = models.CharField(max_length=30)

last_name = models.CharField(max_length=40) email = models.EmailField() def __unicode__(self): return u%s %s % (self.first_name, self.last_name) class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() def __unicode__(self): return self.title Para que los cambios __unicode__() surtan efecto, salga de la shell de Python y entre de nuevo. (Esta es la forma ms sencilla de hacer cambios en el cdigo actual.) Ahora la lista de objetos Publisher es mucho ms fcil de entender: >>> from books.models import Publisher >>> publisher_list = Publisher.objects.all() >>> publisher_list [<Publisher: Apress>, <Publisher: O'Reilly>] Notar que __unicode__() es un buen ejemplo de aadir comportamiento a los modelos. Un modelo Django describe ms que el diseo de la tabla de base de datos de un objeto, sino tambin cualquier funcionalidad de un objeto que sepa hacer. __unicode__() es un ejemplo de funcionalidad de este tipo; un modelo sabe cmo mostrarse a s mismo.

Insertar y actualizar datos


Para insertar una fila en la base de datos, primero debe crear una instancia de su modelo con argumentos de clave, as: >>> p = Publisher(name=Apress, address=2855 Telegraph Ave., city=Berkeley, state_province=CA, country=U.S.A., website=http://www.apress.com/)

Este acto de crear instancias de un modelo de clase no afecta a la base de datos. El registro no se guarda en la base de datos hasta que llame a save():
T T

>>> p.save() Debido a que el modelo utiliza un ID de clave primaria autonumrica, la llamada inicial a save() hace una cosa ms: calcula el valor de clave principal para el registro y lo coloca en el atributo id de la instancia: >>> p.id 52 # this will differ based on your own data Las llamadas posteriores a save() van a guardar el registro, sin crear un nuevo registro (es decir, realizar una instruccin SQL UPDATE en lugar de un INSERT). >>> p.name = Apress Publishing >>> p.save() Tenga en cuenta que todos los campos sern actualizados, y no slo los que han sido cambiados.

Seleccionar objetos
Saber cmo crear y actualizar los registros de base de datos es esencial, pero es probable que las aplicaciones web que usted construya sern de hacer ms consultas de los objetos existentes que de crear nuevos. Ya ha visto una manera de recuperar todos los registros para un determinado modelo: >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: O'Reilly>] Trasladado a SQL sera: SELECT id, name, address, city, state_province, country, website FROM books_publisher;

Filtrar datos
Naturalmente, es raro que desee seleccionar todo de una base de datos a la vez; en la mayora de los casos, usted querr tratar con un subconjunto de los datos. En la API de Django, puede filtrar los datos utilizando el mtodo filter():
T T

>>> Publisher.objects.filter(name=Apress) [<Publisher: Apress>] filter() toma los argumentos que se traducen en las clusulas where de SQL apropiadas. El ejemplo anterior se traducira en algo como:

SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = Apress; Se pueden pasar mltiples argumentos a filter() para reducir an ms las cosas: >>> Publisher.objects.filter(country=U.S.A., state_province=CA) [<Publisher: Apress>] Los mltiples argumentos se traducen en clusulas AND de SQL. As, el ejemplo se traduce en: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = U.S.A. AND state_province = CA; Tenga en cuenta que por defecto las bsquedas utilizan el operador = de SQL para hacer bsquedas de concordancia exacta. Otros tipos de bsqueda estn disponibles: >>> Publisher.objects.filter(name__contains=press) [<Publisher: Apress>] Hay un doble subrayado entre name y contains. Aqu, la parte __contains es traducida por Django en una sentencia LIKE de SQL:
T T

SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name LIKE %press%; Muchos otros tipos de bsquedas estn disponibles, incluyendo icontains (LIKE insensible a maysculas/minsculas), startswith y endswith, y range (consultas BETWEEN de SQL).

Recuperar objetos individuales


El ejemplos de filter() anteriores devolvan un QuerySet, que se puede tratar como una lista. A veces es ms conveniente extraer solamente un objeto individual en lugar de una lista. Para eso est el mtodo get():
T T T T

>>> Publisher.objects.get(name=Apress) <Publisher: Apress> Una consulta que devuelva varios objetos producir una excepcin: >>> Publisher.objects.get(country=U.S.A.) Traceback (most recent call last): MultipleObjectsReturned: get() returned more than one Publisher it returned 2! Lookup parameters were {country: U.S.A.}

Una consulta que no devuelva objetos tambin causar una excepcin: >>> Publisher.objects.get(name=Penguin) Traceback (most recent call last): DoesNotExist: Publisher matching query does not exist. La excepcin DoesNotExist es un atributo de la clase del modelo: Publisher.DoesNotExist. En sus aplicaciones, usted querr atrapar estas excepciones, de esta forma:
T T

try: p = Publisher.objects.get(name=Apress) except Publisher.DoesNotExist: print Apress isnt in the database yet. else: print Apress is in the database.

Ordenar datos
En los ejemplos anteriores, usted puede descubrir que los objetos se devuelven en un orden aparentemente al azar. Estamos simplemente devolviendo los datos en un orden arbitrario elegido por la base de datos. En sus aplicaciones Django, usted probablemente querr pedir sus resultados de acuerdo a un cierto criterio por ejemplo, por orden alfabtico. Para ello, utilizar el mtodo order_by():
T T

>>> Publisher.objects.order_by(name) [<Publisher: Apress>, <Publisher: O'Reilly>] Esto no parece muy diferente del all() del ejemplo anterior, pero el SQL ahora incluye un orden especfico: SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name; Puede ordenar por el campo que quiera: >>> Publisher.objects.order_by(address) [<Publisher: O'Reilly>, <Publisher: Apress>] >>> Publisher.objects.order_by(state_province) [<Publisher: Apress>, <Publisher: O'Reilly>] Para ordenar por mltiples campos usar varios argumentos:

>>> Publisher.objects.order_by(state_province, address) [<Publisher: Apress>, <Publisher: O'Reilly>] Tambin puede especificar orden inverso anteponiendo al nombre del campo un (esto es un signo menos): >>> Publisher.objects.order_by(-name) [<Publisher: O'Reilly>, <Publisher: Apress>] Si bien esta flexibilidad es til, utilizar order_by() todo el tiempo puede ser bastante repetitivo. La mayora de las veces tendr un campo particular por el querr ordenar. En estos casos, Django permite especificar una ordenacin predeterminada en el modelo: class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() def __unicode__(self): return self.name class Meta: ordering = ['name'] En este caso, hemos introducido un nuevo concepto: la clase Meta, que es una clase que est incrustada dentro de la definicin de la clase Publisher. Usted puede utilizar la clase Meta en cualquier modelo para especificar opciones especficas del modelo.
T T

Si se especifica esto, le dice a Django que a menos que se indique un ordenamiento de forma explcita con order_by(), todos los objetos Publisher deben ser ordenados por el campo name cada vez que se recuperen con la API de Base de Datos de Django.

Encadenar bsquedas
Hemos visto como filtrar datos y como ordenarlos. A menudo necesitaremos ambos. En estos casos, encadenar las bsquedas: >>> Publisher.objects.filter(country=U.S.A.).order_by(-name) [<Publisher: O'Reilly>, <Publisher: Apress>]

Esto se convierte a una sentencia SQL con WHERE y ORDER BY: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = U.S.A ORDER BY name DESC;

Trocear datos
Otra necesidad comn es buscar slo un nmero fijo de filas. Imagina que tiene miles de editores en su base de datos, pero que desea mostrar slo el primero. Usted puede hacerlo con esta sintaxis: >>> Publisher.objects.order_by(name)[0] <Publisher: Apress> Esto se traduce en: SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name LIMIT 1; De igual forma, usted puede recuperar un subconjunto especfico de datos: >>> Publisher.objects.order_by(name)[0:2] Esto devuelve 2 objetos, y se traduce en: SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name OFFSET 0 LIMIT 2; Tener en cuenta que el ndice negativo no est soportado: >>> Publisher.objects.order_by(name)[-1] Traceback (most recent call last): AssertionError: Negative indexing is not supported. Esto es fcil de conseguir, sin embargo. Slo cambiar la sentencia order_by() de esta forma: >>> Publisher.objects.order_by(-name)[0]

Actualizar varios objetos en una sentencia

Hemos sealado en la seccin Insercin y actualizacin de datos que el mtodo save() del modelo actualiza todas las columnas de una fila. Dependiendo de su aplicacin, es posible que desee actualizar slo un subconjunto de columnas. Por ejemplo, supongamos que usted desea actualizar la editorial Apress para cambiar el nombre de Apress a Apress Publishing. Usando save(), se vera algo como esto: >>> p = Publisher.objects.get(name=Apress) >>> p.name = Apress Publishing >>> p.save() Esto se traduce en el siguiente SQL: SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = Apress; UPDATE books_publisher SET name = Apress Publishing, address = 2855 Telegraph Ave., city = Berkeley, state_province = CA, country = U.S.A., website = http://www.apress.com WHERE id = 52; El mtodo save() de Django establece todos los valores de las columnas, no slo la columna name. Si est en un entorno en el que otras columnas de la base de datos podran cambiar a causa de algn otro proceso, es ms inteligente cambiar slo la columna que usted necesita. Para ello, utilice el mtodo update() en objetos QuerySet. He aqu un ejemplo: >>> Publisher.objects.filter(id=52).update(name=Apress Publishing) La traduccin a SQL es mucho ms eficiente y no provoca efectos laterales: UPDATE books_publisher SET name = Apress Publishing WHERE id = 52; El mtodo update() funciona en cualquier QuerySet, lo que significa que usted puede editar varios registros de forma masiva. He aqu cmo usted puede cambiar el pas de U.S.A. a USA en todos los registros Publisher:
T T

>>> Publisher.objects.all().update(country=USA) 2 El mtodo update() devuelve un valor: un entero que representa cuntos registros han cambiado. En el ejemplo anterior, fue 2.

Eliminar objetos
Para eliminar un objeto de la base de datos, simplemente llamar al mtodo delete():
T T

>>> p = Publisher.objects.get(name=OReilly) >>> p.delete() >>> Publisher.objects.all() [<Publisher: Apress Publishing>] Tambin puede eliminar objetos de forma masiva llamando al mtodo delete() del resultado de cualquier QuerySet. Esto es similar al mtodo update() que vimos en la ltima seccin: >>> Publisher.objects.filter(country=USA).delete() >>> Publisher.objects.all().delete() >>> Publisher.objects.all() [] Tenga cuidado al borrar sus datos. Como medida de precaucin contra la supresin de todos los datos de una tabla particular, Django requiere que use explcitamente el mtodo all() si desea borrar toda su tabla. Por ejemplo, esto no funciona: >>> Publisher.objects.delete() Traceback (most recent call last): File , line 1, in AttributeError: Manager object has no attribute delete Pero funciona si le aade el mtodo all():
T T

>>> Publisher.objects.all().delete() Si est eliminando slo un subconjunto de datos, no es necesario incluir all(): >>> Publisher.objects.filter(country=USA).delete()

Tutorial de Django V
HTU UTH

12. mayo 2010 - Visitada 1765 veces, 1 hoy Tcnico


HTU UTH

El sitio de administracin de Django


TU UT

Para una cierta clase de sitios Web, una interfaz de administracin es una parte esencial de la infraestructura. Se trata de una interfaz basada en Web, limitada a los administradores del sitio de confianza, que permite la adicin, la edicin, y la eliminacin de contenido del sitio.

Los paquetes django.contrib


La administracin automtica de Django es parte de una gran suite de funcionalidad de Django llamada django.contrib la parte de cdigo de Django que contiene diversas utilidades para el ncleo. Usted puede pensar en django.contrib como el equivalente de Django de la librera estndar de Python. Est integrado con Django de modo que no tenemos que reinventar la rueda en nuestras propias aplicaciones. El sitio de administracin se llama django.contrib.admin. Otras caractersticas disponibles en django.contrib incluyen un sistema de autenticacin de usuarios (django.contrib.auth), soporte para sesiones annimas (django.contrib.sessions), e incluso un sistema de comentarios de usuarios (django.contrib.comments).

Activar la interfaz de administracin


El sitio de administracin de Django es totalmente opcional, ya que slo ciertos tipos de sitios necesitan esta funcionalidad. Eso significa que usted tendr que dar unos pasos para activarlo en su proyecto. En primer lugar, hacer unos cuantos cambios a su archivo de configuracin: 1. Aadir django.contrib.admin a la propiedad INSTALLED_APPS. 2. Asegrese de que INSTALLED_APPS contiene django.contrib.auth, django.contrib.contenttypes, y django.contrib.sessions. El sitio de administracin de Django requiere de estos tres paquetes. 3. Asegrese de que MIDDLEWARE_CLASSES contiene los valores django.middleware.common.CommonMiddleware, django.contrib.sessions.middleware.SessionMiddleware, y django.contrib.auth.middleware.AuthenticationMiddleware. En segundo lugar, ejecutar python manage.py syncdb. Este paso permitir instalar las tablas extra de base de datos que utiliza el interfaz de administracin. La primera vez que ejecute syncdb con django.contrib.auth en INSTALLED_APPS, se le preguntar sobre la creacin de un super-usuario. Si usted no hace esto, tendr que para ejecutar python manage.py createsuperuser por separado para crear una cuenta de usuario administrador, de lo contrario usted no ser capaz de entrar en el sitio de administracin.
T T

En tercer lugar, agregue el sitio de administracin a su URLconf (en urls.py, recuerde). Por defecto, el urls.py generado por django-admin.py startproject contiene el cdigo comentado para la administracin de Django, y todo lo que tiene que hacer es quitar los comentarios.
T T T T T T

# Include these import statements from django.contrib import admin admin.autodiscover() # And include this URLpattern urlpatterns = patterns(, # (r^admin/, include(admin.site.urls)), # ) Con esa poca configuracin, ahora usted puede ver el sitio de administracin de Django en accin. Simplemente ejecute el servidor de desarrollo (python manage.py runserver) y visite http://127.0.0.1:8000/admin/ en su navegador Web.
T T T T

Usar el sitio de administracin


Inicie sesin con el nombre de usuario y contrasea que agreg cuando cre el superusuario. Si usted no puede abrir una sesin, asegrese de que ha creado realmente un super-usuario ejecutando python manage.py createsuperuser.
T T

Una vez que est conectado, lo primero que ver ser la pgina de inicio de administracin. Esta pgina muestra todos los tipos de datos disponibles que se pueden editar en el sitio de administracin. En este punto, ya que no ha activado ninguno de nuestros modelos, la lista es escasa: slo incluye Grupos y Usuarios, que son los dos modelos de administracin por defecto editables. Cada tipo de datos en el sitio de administracin de Django tiene una lista de cambios y un formulario de edicin. Las listas de cambios muestran todos los objetos disponibles en la base de datos, y los formularios de edicin le permiten aadir, cambiar o eliminar registros particulares en su base de datos. Haga clic en el vnculo Cambiar en la fila de los usuarios para cargar la pgina de lista de cambios de los usuarios. Esta pgina muestra todos los usuarios de la base de datos. Pulse un nombre de usuario, y ver el formulario de edicin de ese usuario. Esta pgina le permite cambiar los atributos del usuario.

Aadir modelos al sitio de administracin


Vamos a aadir nuestros propios modelos a la pgina de administracin a fin de que podemos agregar, modificar y eliminar objetos en nuestras tablas de bases de datos personalizadas utilizando esta interfaz agradable.

Vamos a seguir el ejemplo de los libros, donde definimos tres modelos: Publisher, Author, y Book. En el directorio de libros (mysite/books), cree un archivo llamado admin.py, y escriba las siguientes lneas de cdigo:
T T

from django.contrib import admin from mysite.books.models import Publisher, Author, Book admin.site.register(Publisher) admin.site.register(Author) admin.site.register(Book) Este cdigo le indica al sitio de administracin de Django que ofrezca una interfaz para cada uno de estos modelos. Una vez que haya hecho esto, vaya a la pgina de inicio de administracin en su explorador Web (http://127.0.0.1:8000/admin/). Usted debe ver una seccin de Libros con enlaces a los autores, libros y editores. Tendr que reiniciar runserver para que los cambios tengan efecto.
T T

Un aspecto digno de mencionar aqu es el manejo de las claves ajenas y las relaciones muchos-a-muchos por el sitio de administracin, las cuales aparecen en el modelo Book. En la pgina Add Book del sitio de administracin de Django (http://127.0.0.1:8000/admin/books/book/add/), el editor (una ForeignKey) es representado por una caja de seleccin, y el campo de los autores (un ManyToManyField) es representado por un cuadro de seleccin mltiple. Ambos campos estn al lado de un signo ms verde que te permite aadir los registros relacionados de ese tipo. Por ejemplo, si hace clic en el signo ms verde junto al campo Publisher, obtendr una ventana emergente que le permite aadir un editor.

Cmo trabaja el sitio de administracin


Cuando Django carga su URLconf de urls.py al arrancar el servidor, se ejecuta la setencia admin.autodiscover() que aadimos como parte de la activacin de la administracin. Esta funcin itera sobre la configuracin de INSTALLED_APPS y busca un archivo llamado admin.py en cada aplicacin instalada. Si un admin.py existe en una aplicacin dada, se ejecuta el cdigo de ese fichero.
T T T T T T

En el admin.py de nuestra aplicacin books, cada llamada a admin.site.register() simplemente registra el modelo dado con la administracin. El sitio de administracin mostrar una interfaz de edicin/modificacin para cada modelo que se haya registrado de forma explcita.
T T

La aplicacin django.contrib.auth incluye su propio admin.py, por lo que usuarios y grupos se mostraron de forma automtica en la administracin.
T T

El sitio de administracin de Django es slo una aplicacin Django, con sus propios modelos, plantillas, vistas, y patrones URL. Usted puede examinar sus plantillas, vistas, y patrones URL hurgando en django / contrib / admin en su copia del cdigo base de Django.

Hacer campos opcionales


Usted notar probablemente una limitacin los formularios de edicin requieren que se rellenen todos los campos, mientras que en muchos casos le gustara que determinados campos fuesen opcionales. Digamos, por ejemplo, que queremos que nuestro campo email del modelo Author sea opcional, es decir, que se permita una cadena en blanco. En el mundo real, usted no podra tener una direccin de correo electrnico en archivo para cada autor. Para especificar que el campo de correo electrnico es opcional, modificar el modelo Author. Basta con aadir blank = True para el campo email, as:
T T

class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True) Al aadir blank = True, hemos comenzado la expansin de nuestro modelo ms all de una simple definicin de la tabla de base de datos. Ahora, nuestra clase de modelo est empezando a convertirse en una rica coleccin de conocimiento sobre lo que los objetos Author son y qu pueden hacer. No slo est el campo email representado por una columna VARCHAR en la base de datos, sino que es tambin un campo opcional en contextos como el sitio de administracin de Django.

Hacer a fechas y campos numricos opcionales


SQL tiene su propia forma de especificar los valores en blanco, un valor especial llamado NULL. NULL puede significar desconocido o invlido, o algn otro significado especfico de la aplicacin. En SQL, un valor de NULL es diferente de una cadena vaca, al igual que el objeto especial de Python None es diferente de la una cadena vaca (). Esto puede causar confusin y ambigedad no deseados: Por qu este disco tiene un valor NULL, pero este otro tiene una cadena vaca? Hay una diferencia, o se introdujeron los datos de manera distinta?. Y Cmo puedo obtener todos los registros que tienen un valor en blanco, debera buscar tanto los registros NULL como las cadenas vacas, o debo elegir slo los que tienen cadenas vacas? Para evitar esa ambigedad, Django genera automticamente sentencias CREATE TABLE aadiendo un valor explcito NOT NULL a cada definicin de columna. En la mayora de los casos, este comportamiento predeterminado es ptimo para su aplicacin y le ahorrar dolores de cabeza por inconsistencia de los datos. Y funciona muy bien con el resto de Django, tales como el sitio de administracin de Django, que

inserta una cadena vaca (no un valor NULL) cuando se deja un campo de carcter en blanco. Pero hay una excepcin con los tipos de columna de base de datos que no aceptan cadenas vacas como valores vlidos, tales como fechas, horas y nmeros. Si intenta insertar una cadena vaca en una columna de fecha o nmero entero, lo ms probable es obtener un error de base la de datos. En este caso, NULL es la nica manera de especificar un valor vaco. En los modelos Django, usted puede especificar que se permite NULL aadiendo null = True a un campo. En resumen, si desea permitir valores en blanco en un campo de fecha (por ejemplo, DateField, TimeField, DateTimeField) o campo numrico (por ejemplo, IntegerField, DecimalField, FloatField), tendr que utilizar tanto null = True como blank = True.
T T T T

Cambiemos nuestro modelo Book para permitir una fecha de publicacin en blanco: class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField(blank=True, null=True) Agregar null = True es ms complicado que aadir blank = True, porque null = True cambia la semntica de la base de datos, es decir, cambia la sentencia CREATE TABLE para eliminar el NOT NULL del campo publication_date. Para completar este cambio, necesitaremos actualizar la base de datos.
T T

Por varias razones, Django no trata de automatizar los cambios en los esquemas de base de datos, por lo que es su propia responsabilidad ejecutar el ALTER TABLE adecuado siempre que se realice un cambio a un modelo. Recuerde que puede utilizar python manage.py dbshell para entrar en la shell de su servidor de base de datos. He aqu cmo quitar el NOT NULL en este caso en particular: ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL; Ahora el formulario de edicin Add Book debera permitir valores de fecha de publicacin vacos.

Personalizar etiquetas de campo


En los formularios de edicin del sitio de administracin, la etiqueta de cada campo se genera a partir del nombre de campo del modelo. El algoritmo es simple: Django simplemente reemplaza los guiones bajos con espacios y coloca en maysculas el primer carcter. As, por ejemplo, el campo publication_date del modelo Book tiene la fecha Publicacin Date. Sin embargo, los nombres de campo no siempre se prestan a etiquetas de campo agradables en administracin, as que en algunos casos es posible que desee personalizar una etiqueta. Usted puede hacer esto especificando verbose_name en el
T T

campo del modelo adecuado. Por ejemplo, as es cmo podemos cambiar la etiqueta del campo Author.email a e-mail, con guin: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name=e-mail) Por ltimo, tenga en cuenta que puede pasar el verbose_name como un argumento de posicin, para una sintaxis ms compacta. Este ejemplo es equivalente al anterior: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(e-mail, blank=True) Esto no funcionar con campos ManyToManyField o ForeignKey, debido a que requieren que el primer argumento sea una clase modelo. En esos casos, especificar verbose_name explcitamente.
T T T T

Personalizar clases ModelAdmin


Los cambios que hemos hecho hasta ahora blank = True, null = True, y verbose_name- son realmente cambios de nivel de modelo, no cambios de nivel de administracin. Es decir, estos cambios son, fundamentalmente, una parte del modelo y slo para ser utilizados por el sitio de administracin, no hay nada especfico de administracin en ellos. Ms all de estos, el sitio de administracin de Django ofrece una gran cantidad de opciones que permiten personalizar la forma en que el sitio de administracin trabaja para un modelo en particular. Tales opciones residen en clases ModelAdmin, que son clases que contienen la configuracin de un modelo especfico en una instancia del sitio de administracin especfica.
T T

Personalizar listas de cambios


Entremos en la personalizacin de administracin, especificando los campos que se muestran en la lista de cambios para el modelo Author. De forma predeterminada, la lista de cambios muestra el resultado de __unicode__() para cada objeto.
T T

Podemos mejorar este comportamiento predeterminado, aadiendo algunos campos ms a la muestra de la lista de cambios. Sera til, por ejemplo, ver cada e-mail del autor en esta lista, y sera bueno poder ordenarla por nombre y apellido. Para que esto ocurra, vamos a definir una clase ModelAdmin para el modelo de Autor. Esta clase es la clave para personalizar la administracin, y una de las cosas ms bsicas que le permite hacer es especificar la lista de campos a mostrar en las pginas de lista de cambios. Editar admin.py para realizar estos cambios:
T T T T

from django.contrib import admin from mysite.books.models import Publisher, Author, Book class AuthorAdmin(admin.ModelAdmin): list_display = (first_name, last_name, email) admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book) Volver a cargar la pgina de lista de cambios del autor, y ver que ahora se muestran tres columnas: el nombre, el apellido y la direccin de correo electrnico. Adems, cada una de esas columnas es ordenable haciendo clic en el encabezado de la columna. Ahora agreguemos una barra de bsqueda simple. Aadir a search_fields a AuthorAdmin, as:
T T

class AuthorAdmin(admin.ModelAdmin): list_display = (first_name, last_name, email) search_fields = (first_name, last_name) Actualice la pgina en su navegador, y debera ver una barra de bsqueda en la parte superior. Hemos incluido una barra de bsqueda que busca en los campos first_name y last_name. Ahora agreguemos algunos filtros de fecha para nuestra pgina de lista de cambios del modelo Book: from django.contrib import admin from mysite.books.models import Publisher, Author, Book class AuthorAdmin(admin.ModelAdmin): list_display = (first_name, last_name, email) search_fields = (first_name, last_name) class BookAdmin(admin.ModelAdmin): list_display = (title, publisher, publication_date) list_filter = (publication_date,) admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book, BookAdmin) Hemos utilizado list_filter, que fija en una tupla los campos a utilizar para crear filtros en el lado derecho de la pgina de lista de cambios. Para los campos fecha, Django proporciona accesos directos para filtrar la lista por Hoy, ltimos 7 das, Este mes, y Este ao.
T T

list_filter tambin trabaja en campos de otros tipos, no slo DateField. (Pruebe con los campos BooleanField y ForeignKey, por ejemplo.) Los filtros se muestran siempre que haya por lo menos dos valores a elegir. Otra manera de ofrecer filtros de fecha es utilizar la opcin de administracin date_hierarchy, as:
T T

class BookAdmin(admin.ModelAdmin): list_display = (title, publisher, publication_date) list_filter = (publication_date,) date_hierarchy = publication_date Tenga en cuenta que date_hierarchy toma una cadena, no una tupla, porque slo un campo de fecha puede utilizarse para la jerarqua. Por ltimo, vamos a cambiar el orden por defecto en que se muestran los libros en la pgina de lista de cambios a siempre ordenado descendente por la fecha de su publicacin. class BookAdmin(admin.ModelAdmin): list_display = (title, publisher, publication_date) list_filter = (publication_date,) date_hierarchy = publication_date ordering = (-publication_date,) Usando estas opciones, usted puede hacer una interfaz de edicin de datos muy potente, lista para produccin, con slo unas pocas lneas de cdigo.

Personalizar los formularios de edicin


En primer lugar, vamos a personalizar la manera en que se ordenan los campos. De forma predeterminada, el orden de los campos en un formulario de edicin corresponde al orden en que estn definidas en el modelo. Nosotros podemos cambiar eso utilizando la opcin fields en nuestra subclase ModelAdmin:
T T T T

class BookAdmin(admin.ModelAdmin): list_display = (title, publisher, publication_date) list_filter = (publication_date,) date_hierarchy = publication_date ordering = (-publication_date,) fields = (title, authors, publisher, publication_date) Otra cosa til de la opcin fields es que permite excluir a ciertos campos de la edicin. Slo dejando fuera los campo(s) que desea excluir. Por ejemplo, en nuestra base de datos de libros, se podra impedir que el campo publication_date fuese editable: class BookAdmin(admin.ModelAdmin):

list_display = (title, publisher, publication_date) list_filter = (publication_date,) date_hierarchy = publication_date ordering = (-publication_date,) fields = (title, authors, publisher) Otro uso comn de personalizar los formularios de edicin tiene que ver con los campos muchos a muchos. El sitio de administracin representa cada ManyToManyField como una caja de seleccin mltiple. Si desea seleccionar varios elementos, hay que mantener pulsada la tecla Control. El sitio de administracin amablemente inserta un fragmento de texto que explica esto, pero, an as, se hace difcil de manejar cuando su campo contiene cientos de opciones. La solucin del sitio de administracin es filter_horizontal.
T T T T

class BookAdmin(admin.ModelAdmin): list_display = (title, publisher, publication_date) list_filter = (publication_date,) date_hierarchy = publication_date ordering = (-publication_date,) filter_horizontal = (authors,) Recomendamos el uso filter_horizontal para cualquier ManyToManyField que tenga ms de diez elementos. Es mucho ms fcil de utilizar.Tambin, recuerde que puede usar filter_horizontal en mltiples campos, especificando solamente cada nombre en la tupla. Las clases ModelAdmin tambin tienen una opcin filter_vertical. Funciona exactamente como filter_horizontal, pero la interfaz coloca las dos casillas verticalmente en vez de horizontalmente. Es una cuestin de gusto personal.
T T T T

filter_horizontal y filter_vertical funcionan slo en los campos ManyToManyField, no en campos ForeignKey. Por defecto, el sitio de administracin usa <select> simples para los campos ForeignKey, pero, como para ManyToManyField, a veces usted no quiere incurrir en la sobrecarga de tener que seleccionar todos los objetos relacionados con la pantalla en el men desplegable. Por ejemplo, si nuestra base de datos de libros crece para incluir a miles de editores, el formulario Add Book podra tardar bastante en cargar, ya que tiene que cargar cada editor a mostrar en el cuadro <select>.
T T T T T T T T

Puedes solucionar este problema con una opcin llamada raw_id_fields. Ponga esto en una tupla de nombres de campo ForeignKey, y los campos se mostrarn en el administrador con una caja de entrada de texto simple (<input type = text>) en lugar de un <select>.
T T T T

class BookAdmin(admin.ModelAdmin): list_display = (title, publisher, publication_date) list_filter = (publication_date,) date_hierarchy = publication_date ordering = (-publication_date,) filter_horizontal = (authors,) raw_id_fields = (publisher,)

Qu introducira en este cuadro de entrada? El identificador de la base de datos del editor.Teniendo en cuenta que los seres humanos normalmente no memorizan identificadores base de datos, hay un icono en el que puede hacer clic para iniciar una ventana desde la que puede seleccionar el editor.

Usuarios, grupos y permisos


Ya que est conectado como super-usuario, tiene acceso a crear, editar y eliminar cualquier objeto. Naturalmente, los diferentes entornos requieren de sistemas de autorizacin diferentes, no todos pueden o deben ser un superusuario. El sitio de administracin de Django utiliza un sistema de permisos que se puede utilizar para dar acceso especfico a los usuarios a las partes de la interfaz que necesitan. Estas cuentas de usuario estn destinadas a ser lo suficientemente generales como para utilizarse fuera de la interfaz de administracin, pero las trataremos como cuentas de usuario de administracin por ahora. Puede editar los usuarios y los permisos a travs de la interfaz de administracin al igual que cualquier otro objeto. Los objetos de usuario tiene los campos nombre de usuario estndar, contrasea, e-mail, y nombre real, junto con un conjunto de campos que definen lo que el usuario puede hacer en la interfaz de administracin. En primer lugar, hay un conjunto de 3 banderas boolean:

El flag activo controla si el usuario est activo. El flag staff controla si el usuario tiene permiso para acceder a la interfaz de administracin. El flag superusuario proporciona al usuario acceso completo a agregar, crear y eliminar cualquier elemento de la interfaz de administracin.

Los usuarios de administracin normales es decir, los miembros activos, no superusuarios se les concede acceso de administracin a travs de los permisos asignados. Cada objeto editable a travs de la interfaz de administracin (por ejemplo, libros, autores, editores) tiene tres permisos: crear, editar y eliminar. La asignacin de permisos a un usuario concede al usuario el correspondiente nivel de acceso. Al crear un usuario, dicho usuario no tiene permisos. Por ejemplo, usted puede dar a un usuario permiso para agregar y cambiar los editores, pero no para eliminarlos. Tenga en cuenta que estos permisos se definen por el modelo, no por objeto, de forma que usted diga, Juan puede hacer cambios en cualquier libro, pero no le permite decir, Juan puede hacer los cambios de cualquier libro publicado por Apress. Tambin puede asignar usuarios a grupos. Un grupo es simplemente un conjunto de permisos que se aplican a todos los miembros de ese grupo. Los grupos son tiles para la concesin de permisos idnticos a un subconjunto de usuarios.

Tutorial de Django VI
HTU UTH

16. julio 2010 - Visitada 1692 veces, 2 hoy Tcnico


HTU UTH

Formularios
TU UT

Los formularios HTML son la columna vertebral de sitios Web interactivos. Este captulo comprende cmo se puede utilizar Django para acceder a los datos de formulario emitidos por el usuario, validarlos, y hacer algo con ellos. En el camino, cubriremos los objetos HttpRequest y Form.

Obtener datos del objeto Request


Los objetos HttpRequest, tienen una serie de atributos y de mtodos que son interesantes y debera familiarizarse con ellos para saber lo que es posible hacer con ellos. Puede usar estos atributos para obtener informacin acerca de la peticin actual (por ejemplo el usuario / navegador web que est cargando la pgina actual en su sitio Django) en el momento en que se ejecuta la la funcin de la vista.

Informacin sobre la URL


Los objetos HttpRequest contienen varias piezas de informacin sobre la URL solicitada actualmente: Usar siempre los atributos / mtodos en lugar de codificar las direcciones URL en sus vista. Esto hace que el cdigo sea ms flexible y que pueda ser reutilizado en otros lugares. He aqu un simple ejemplo: # BAD! def current_url_view_bad(request): return HttpResponse(Welcome to the page at /current/) # GOOD def current_url_view_good(request): return HttpResponse(Welcome to the page at %s % request.path)

Otra informacin sobre la peticin


request.META es un diccionario Python que contiene todas las cabeceras HTTP disponibles para la solicitud dada, incluyendo la direccin IP del usuario y el agente de

usuario (generalmente el nombre y la versin del navegador Web). Las siguientes son algunas claves comunes en este diccionario:

HTTP_REFERER: La URL de referencia, si la hubiese. HTTP_USER_AGENT: La cadena de agente de usuario (si existe) del navegador del usuario. Esto se parecer a algo como lo siguiente: Mozilla 5.0 (X11; U; Linux i686) Gecko/20080829 Firefox/2.0.0.17 REMOTE_ADDR: La direccin IP del cliente.

Usted debe usar una clusula try / except, o un mtodo get() para manejar el caso de claves indefinidas, como en este ejemplo: # BAD! def ua_display_bad(request): ua = request.META['HTTP_USER_AGENT'] # Might raise KeyError! return HttpResponse(Your browser is %s % ua) # GOOD (VERSION 1) def ua_display_good1(request): try: ua = request.META['HTTP_USER_AGENT'] except KeyError: ua = unknown return HttpResponse(Your browser is %s % ua) # GOOD (VERSION 2) def ua_display_good2(request): ua = request.META.get(HTTP_USER_AGENT, unknown) return HttpResponse(Your browser is %s % ua) Le animamos a escribir una pequea vista que muestra todos los datos de request.META para que pueda conocer lo que est disponible. Se podra parecer a esto: def display_meta(request): values = request.META.items() values.sort() html = [] for k, v in values: html.append(<tr><td>%s</td><td>%s</td></tr> % (k, v)) return HttpResponse(<table>%s</table> % \n.join(html))

Informacin sobre datos emitidos


Ms all de los metadatos bsicos acerca de la solicitud, los objetos HttpRequest tienen dos atributos que contienen la informacin que enva el usuario: request.GET y request.POST. Ambas son objetos como diccionarios que le dan acceso a los datos GET y POST. Los datos POST generalmente son emitidos desde un formulario HTML, mientras que los datos GET pueden provenir de un formulario o del querystring de la URL de la pgina.

Un ejemplo simple de gestin de formulario


Creemos una vista simple que permita a los usuarios buscar en nuestra base de datos de libros por el ttulo. En general, hay dos partes para el desarrollo de un formulario: la interfaz de usuario HTML y el cdigo de la vista que procesa los datos presentados. La primera parte es fcil, vamos a crear una vista que muestre un formulario de bsqueda: from django.shortcuts import render_to_response def search_form(request): return render_to_response(search_form.html) Esta vista puede residir en cualquier parte de su ruta de acceso Python. Para este ejemplo, colocarla en books/views.py.
T T

La plantilla de acompaamiento, search_form.html, podra tener este aspecto:


T T

<html> <head> <title>Search</title> </head> <body> <form action=/search/ method=get> <input type=text name=q> <input type=submit value=Search> </form> </body> </html> El patrn URL en urls.py podra ser algo como esto:
T T

urlpatterns = patterns(, # (r^search-form/$, views.search_form), # ) Ahora, si ejecuta el runserver y visita http://127.0.0.1:8000/search-form/, ver la interfaz de bsqueda. Bastante simple.
T T

Intente emitir el formulario, sin embargo, y obtendr un error 404 de Django. El formulario apunta a la URL /search/, que an no ha sido implementada. Vamos a arreglar eso con una segunda funcin de vista: # urls.py urlpatterns = patterns(, # (r^search-form/$, views.search_form), (r^search/$, views.search), # ) # views.py def search(request): if q in request.GET: message = You searched for: %r % request.GET['q'] else: message = You submitted an empty form. return HttpResponse(message) Por el momento, esto slo muestra el trmino de bsqueda del usuario de modo que pueda asegurarse que los datos se presentan a Django correctamente y para que pueda tener una idea de cmo los trminos de la bsqueda fluyen a travs del sistema. En resumen, esto es lo que sucede: 1. El formulario HTML define una variable q. Cuando se emite, el valor de q se enva a travs de GET (method = get) a la URL /search/. 2. La vista Django que se encarga de la direccin /search/ tiene acceso al valor de q en request.GET. Tenga en cuenta que comprobamos explcitamente que q existe en request.GET. Como hemos sealado, usted no debe confiar en nada presentado por los

usuarios. Si no ha aadido esta verificacin, cualquier emisin de un formulario vaco lanzara KeyError en la vista: # BAD! def bad_search(request): # The following line will raise KeyError if q hasnt # been submitted! message = You searched for: %r % request.GET['q'] return HttpResponse(message) Los datos POST funcionan de la misma manera que los datos GET. Cul es la diferencia entre GET y POST? Utilice GET cuando el acto de emitir el formulario es slo una solicitud para obtener datos. Utilice POST siempre que el acto de emitir el formulario tenga algunos efectos secundarios de actualizacin de datos o enviar un email, o algo ms de la simple exhibicin de los datos. En nuestro ejemplo de bsqueda de libro, estamos utilizando GET porque la consulta no cambia ningn dato en nuestro servidor. Ahora que hemos verificado que request.GET se est pasando correctamente, vamos a conectar la consulta de bsqueda del usuario con nuestra base de datos de libros (de nuevo, en views.py):
T T

from django.http import HttpResponse from django.shortcuts import render_to_response from mysite.books.models import Book def search(request): if q in request.GET and request.GET['q']: q = request.GET['q'] books = Book.objects.filter(title__icontains=q) return render_to_response(search_results.html, {books: books, query: q}) else: return HttpResponse(Please submit a search term.) El cdigo de la plantilla search_results.html podra ser algo como esto:
T T

<p>You searched for: <strong>{{ query }}</strong></p> {% if books %} <p>Found {{ books|length }} book{{ books|pluralize }}.</p> <ul> {% for book in books %} <li>{{ book.title }}</li> {% endfor %}

</ul> {% else %} <p>No books matched your search criteria.</p> {% endif %}

Mejorar nuestro ejemplo de gestin de formulario simple


En primer lugar, nuestra gestin de la vista search() de una consulta vaca es pobre estamos mostrando solo un mensaje Por favor, enve un trmino de bsqueda, que requiere que el usuario pulse el botn Atrs del navegador. Esto es horrible y poco profesional. Sera mucho mejor volver a mostrar el formulario, con un error sobre l, de modo que el usuario pueda volver a intentarlo inmediatamente. La forma ms sencilla de hacerlo sera la de renderizar la plantilla de nuevo, de esta forma: from django.http import HttpResponse from django.shortcuts import render_to_response from mysite.books.models import Book def search_form(request): return render_to_response(search_form.html) def search(request): if q in request.GET and request.GET['q']: q = request.GET['q'] books = Book.objects.filter(title__icontains=q) return render_to_response(search_results.html, {books: books, query: q}) else: return render_to_response(search_form.html, {error: True}) Hemos mejorado search() renderizando la plantilla search_form.html de nuevo, si la consulta est vaca. Y ya que tenemos que mostrar un mensaje de error en esa plantilla, pasamos una variable de plantilla. Ahora podemos editar search_form.html para comprobar la variable de error: <html> <head> <title>Search</title>

</head> <body> {% if error %} <p style=color: red;>Please submit a search term.</p> {% endif %} <form action=/search/ method=get> <input type=text name=q> <input type=submit value=Search> </form> </body> </html> Todava podemos utilizar esta plantilla desde nuestra vista original, search_form(), ya que search_form() no pasa el error a la plantilla el mensaje de error no se mostrar en ese caso. Con este cambio es una aplicacin mejor, pero ahora surge la pregunta: es una vista search_form() dedicada realmente necesaria? Tal como est, una solicitud a la direccin URL /search/ (sin los parmetros GET) mostrar el formulario vaco (pero con un error). Podemos eliminar la vista search_form(), junto con su patrn URL asociado, siempre y cuando cambiemos search() para ocultar el mensaje de error cuando alguien visite /search/ sin parmetros GET: def search(request): error = False if q in request.GET: q = request.GET['q'] if not q: error = True else: books = Book.objects.filter(title__icontains=q) return render_to_response(search_results.html, {books: books, query: q}) return render_to_response(search_form.html, {error: error}) En esta vista actualizada, si un usuario visita /search/ sin parmetros GET, ver el formulario de bsqueda sin mensaje de error. Si un usuario enva el formulario con un valor vaco para q, ver el formulario de bsqueda con un mensaje de error. Y, por ltimo, si un usuario enva el formulario con un valor no vaco de q, ver los resultados de bsqueda.

Podemos hacer una mejora final a esta aplicacin, para quitar un poco de redundancia. Ahora que hemos mezclado las dos vistas y URLs en una sola y /search/ maneja tanto la pantalla del formulario de bsqueda como la del resultado, el formulario HTML en search_form.html no tiene que codificar una URL a pelo. En lugar de esto:
T T

puede cambiarse a: El action = significa Enviar el formulario a la misma URL que la pgina actual. Con este cambio, usted no tendr que acordarse de cambiar la accin, incluso si alguna vez la vista search() apunta a otra URL.

Validacin simple
Nuestro ejemplo de bsqueda es todava bastante simple, especialmente en trminos de validacin de sus datos, hacemos una mera comprobacin para asegurar que la consulta de bsqueda no est vaca. Muchos de los formularios HTML incluyen un nivel de validacin que es ms complejo que asegurar que el valor no est vaco. Todos hemos visto la siguientes mensajes de error en los sitios Web: Por favor introduzca una direccin de correo electrnico. Por favor, introduzca un cdigo postal de cinco dgitos vlido EE.UU. Por favor, introduzca una fecha vlida con formato AAAA-MM-DD. Por favor, introduzca una contrasea que sea por lo menos de 8 caracteres de longitud y contenga al menos un nmero. Vamos a afinar la vista search() para validar que el trmino de bsqueda sea menor o igual a 20 caracteres de largo. Cmo podemos hacerlo? Lo ms sencillo sera integrar la lgica directamente en la vista, as: def search(request): error = False if q in request.GET: q = request.GET['q'] if not q: error = True elif len(q) > 20: error = True else: books = Book.objects.filter(title__icontains=q) return render_to_response(search_results.html,{books: books, query: q}) return render_to_response(search_form.html, {error: error})

Ahora bien, si se intenta emitir una consulta de bsqueda mayor de 20 caracteres de largo, obtendr un mensaje de error. Pero ese mensaje de error en search_form.html actualmente dice: Por favor, introduzca un trmino de bsqueda., as que tendremos que cambiarlo para ser exactos en ambos casos (una bsqueda vaca o un trmino de bsqueda demasiado largo).
T T

<html> <head> <title>Search</title> </head> <body> {% if error %} <p style=color: red;> Please submit a search term 20 characters or shorter. </p> {% endif %} <form action=/search/ method=get> <input type=text name=q> <input type=submit value=Search> </form> </body> </html> Hay algo mal en esto. Nuestro nico mensaje de error es potencialmente confuso. Por qu el mensaje de error para un valor vaco menciona nada sobre un lmite de 20 caracteres? Los mensajes de error deben ser especficos y claros. El problema es que estamos utilizando un solo valor boolean para el error, cuando habra que utilizar una lista de cadenas de mensajes de error. He aqu cmo podemos solucionarlo: def search(request): errors = [] if q in request.GET: q = request.GET['q'] if not q: errors.append(Enter a search term.) elif len(q) > 20:

errors.append(Please enter at most 20 characters.) else: books = Book.objects.filter(title__icontains=q) return render_to_response(search_results.html, {books: books, query: q}) return render_to_response(search_form.html, {errors: errors}) Entonces tenemos que hacer un pequeo ajuste en la plantilla search_form.html para reflejar que se pas una lista de errores, en lugar de un error boolean:
T T

<html> <head> <title>Search</title> </head> <body> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action=/search/ method=get> <input type=text name=q> <input type=submit value=Search> </form> </body> </html>

Hacer un formulario de contacto


Aunque hemos reiterado en el ejemplo del formulario de bsqueda de libros varias veces y lo hemos mejorado, sigue siendo muy sencillo: basta con un solo campo, q. Al ser tan simple, ni siquiera usamos la librera de formularios de Django para tratar con l. Pero las formas ms complejas requieren tratamientos ms complejos, y ahora vamos a desarrollar algo ms complejo: un formulario de contacto de la web que permite a los usuarios del sitio envar comentarios, junto con un e-mail de retorno. Despus que el formulario es emitido y los datos son validados, automticamente le enviaremos un mensaje por correo electrnico al personal del sitio.

Empezaremos con nuestra plantilla, contact_form.html:


T T

<html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action=/contact/ method=post> <p>Subject: <input type=text name=subject></p> <p>Your e-mail (optional): <input type=text name=e-mail></p> <p>Message: <textarea name=message rows=10 cols=50></textarea></p> <input type=submit value=Submit> </form> </body> </html> Hemos definido tres campos: el asunto, la direccin de correo electrnico y el mensaje. El segundo es opcional, pero los otros dos campos son obligatorios. Tenga en cuenta que estamos usando method = post aqu en lugar de method = get ya que este formulario de emisin tiene un efecto secundario que enva un e-mail. Si seguimos el camino establecido por nuestra vista search() de la seccin anterior, una versin de nuestra vista contact() podra tener este aspecto: from django.core.mail import send_mail from django.http import HttpResponseRedirect from django.shortcuts import render_to_response def contact(request): errors = [] if request.method == POST: if not request.POST.get(subject, ):

errors.append(Enter a subject.) if not request.POST.get(message, ): errors.append(Enter a message.) if request.POST.get(e-mail) and @ not in request.POST['e-mail']: errors.append(Enter a valid e-mail address.) if not errors: send_mail(request.POST['subject'], request.POST['message'], request.POST.get(e-mail, noreply@example.com), ['siteowner@example.com'], ) return HttpResponseRedirect(/contact/thanks/) return render_to_response(contact_form.html,{errors: errors}) Varias cosas nuevas estn sucediendo aqu:

Comprobamos que request.method es POST. Esto ser cierto slo en el caso de una emisin del formulario, no ser cierto si alguien est solamente viendo el formulario de contacto. Esto hace que sea una buena forma de aislar el caso de pantalla del formulario del caso detransformacin del formulario. En lugar de request.GET, estamos usando request.POST para acceder a los datos del formulario emitido. Esto es necesario porque el cdigo de contact_form.html usa method = post. Contamos con dos campos obligatorios, asunto y mensaje, as que tenemos que validar ambos. Notar que estamos utilizando request.POST.get() y proporcionando una cadena en blanco como el valor por defecto. Aunque el campo de correo electrnico no es obligatorio, debemos an validarlo si es emitido. Nuestro algoritmo de validacin aqu es frgil estamos comprobando que la cadena contiene un carcter @. En el mundo real, necesitaramos una validacin ms robusta. Estamos usando la funcin django.core.mail.send_mail para enviar un email. Esta funcin tiene cuatro argumentos necesarios: el asunto del e-mail, el cuerpo del correo electrnico, la direccin del emisor, y una lista de direcciones de los destinatarios. send_mail est contenida en la clase de Django EmailMessage, que proporciona caractersticas avanzadas tales como archivos adjuntos, emails multiplart, y el control total de los encabezados del correo electrnico. Despus de enviar el e-mail, redirigimos a una pgina de xito devolviendo un objeto HttpResponseRedirect. Usted siempre debe enviar una redireccin para el xito de las peticiones POST. Es una de las mejores prcticas del desarrollo web.

Esto vista funciona, pero las funciones de validacin son enrevesadas. Imagine la tramitacin de un formulario con una docena de campos, de verdad quieres tener que escribir todas esas sentencias if? Otro problema es volver a mostrar el formulario. En el caso de errores de validacin, es mejor prctica volver a mostrar el formulario con los datos presentados anteriormente ya rellenados para que el usuario puede ver lo que hizo mal (y no tener que volver a introducir los datos en los campos que ha emitido correctamente). Nosotros manualmente podramos pasar los datos POST de nuevo a la plantilla, pero habra que editar cada campo HTML para insertar el valor adecuado en el lugar adecuado: # views.py def contact(request): errors = [] if request.method == POST: if not request.POST.get(subject, ): errors.append(Enter a subject.) if not request.POST.get(message, ): errors.append(Enter a message.) if request.POST.get(e-mail) and @ not in request.POST['e-mail']: errors.append(Enter a valid e-mail address.) if not errors: send_mail( request.POST['subject'], request.POST['message'], request.POST.get(e-mail, noreply@example.com), ['siteowner@example.com'], ) return HttpResponseRedirect(/contact/thanks/) return render_to_response(contact_form.html, {errors: errors,subject: request.POST.get(subject, ), message: request.POST.get(message, ),e-mail: request.POST.get(e-mail, ), }) # contact_form.html <html> <head>

<title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action=/contact/ method=post> <p>Subject: <input type=text name=subject value={{ subject }}></p> <p>Your e-mail (optional): <input type=text name=e-mail value={{ e-mail }}> </p> <p>Message: <textarea name=message rows=10 cols=50> **{{ message }}** </textarea> </p> <input type=submit value=Submit> </form> </body> </html> Se trata de una gran cantidad de cdigo, e introduce un montn de posibilidades de error humano. Veremos alguna librera de alto nivel que gestione las tareas relacionadas con los formularios y la validacin.

Su primera clase de formulario


Django viene con una librera de formularios, llamada django.forms, que se encarga de muchas de las cuestiones que hemos estado viendo en este captulo desde la muestra de formularios HTML a la validacin. Volvamos a hacer nuestro formulario de contacto utilizando el marco de formularios de Django. La principal manera de utilizar el marco de formularios es definir una clase Form por cada

HTML. En nuestro caso, slo tenemos una , as que tendremos una clase Form. Esta clase puede residir en cualquier lugar, incluyendo directamente en el archivo views.py, pero la convencin es mantener las clases Form en un archivo llamado forms.py. Cree este archivo en el mismo directorio que el views.py, y escriba lo siguiente:
T T T T

from django import forms class ContactForm(forms.Form): subject = forms.CharField() e-mail = forms.EmailField(required=False) message = forms.CharField() Esto es bastante intuitivo, y es similar a la sintaxis de modelo de Django. Cada campo en el formulario est representado por un tipo de clase Field Charfield y EmailField son los nicos tipos Field utilizados aqu como atributos de una clase Form. Cada campo es obligatorio por defecto, as que para hacer e-mail opcional, especificamos required = False. Vayamos al intrprete interactivo de Python y veamos lo que esta clase puede hacer. Lo primero que puede hacer es mostrarse como HTML: <<< from contact.forms import ContactForm <<< f = ContactForm() <<< print f <tr><th><label for=id_subject>Subject:</label></th><td> <input type=text name=subject id=id_subject /></td></tr> <tr><th><label for=id_e-mail>E-mail:</label></th><td> <input type=text name=e-mail id=id_e-mail /></td></tr> <tr><th><label for=id_message>Message:</label></th><td> <input type=text name=message id=id_message /></td></tr> Django aade una etiqueta a cada campo, junto con las etiquetas para accesibilidad. La idea es hacer que el comportamiento por defecto sea tan satisfactorio como sea posible. Esta es la salida por defecto en el formato de un <table> HTML, pero hay otras salidas preconstruidas: <<< print f.as_ul() <li><label for=id_subject>Subject:</label> <input type=text name=subject id=id_subject /></li> <li><label for=id_e-mail>E-mail:</label> <input type=text name=e-mail id=id_e-mail /></li> <li><label for=id_message>Message:</label> <input type=text name=message id=id_message /></li> <<< print f.as_p() &ltp>&ltlabel for=id_subject>Subject:&lt/label> &ltinput type=text name=subject id=id_subject />&lt/p>

&ltp>&ltlabel for=id_e-mail>E-mail:&lt/label> &ltinput type=text name=e-mail id=id_e-mail />&lt/p> &ltp>&ltlabel for=id_message>Message:&lt/label> &ltinput type=text name=message id=id_message />&lt/p> Tenga en cuenta que la etiquetas de apertura y cierre <table>, <ul>, y <form> no son incluidas en la salida, de forma que usted puede agregar las filas adicionales si es necesario. Estos mtodos son mtodos abreviados para el caso comn de mostrar todo el formulario. Usted tambin puede mostrar el cdigo HTML de un campo particular: <<< print f['subject'] <input type=text name=subject id=id_subject /> <<< print f['message'] <input type=text name=message id=id_message /> La segunda cosa que podemos hacer con los objetos Form es validar los datos. Para ello, crear un nuevo objeto Form y pasarle un diccionario de datos que asigne los nombres de campo a los datos: <<< f = ContactForm({subject: Hello, e-mail: adrian@example.com, message: Nice site!}) Una vez ha asociado los datos con una instancia Form, ha creado un Form bound (ligado): <<< f.is_bound True Llame al mtodo is_valid() de cualquier Form ligado para averiguar si sus datos son vlidos. Hemos pasado un valor vlido para cada campo, por lo que el formulario en su totalidad es vlido: <<< f.is_valid() True Si no se pasa el campo de correo electrnico, sigue siendo vlido, porque hemos especificado required = False para ese campo: <<< f = ContactForm({subject: Hello, message: Nice site!}) <<< f.is_valid() True Pero si dejamos fuera el asunto o el mensaje, el formulario ya no es vlido: <<< f = ContactForm({subject: Hello}) <<< f.is_valid() False <<< f = ContactForm({subject: Hello, message: })

<<< f.is_valid() False Usted puede ver los detalles obteniendo mensajes de error especficos por campo: <<< f = ContactForm({subject: Hello, message: }) <<< f['message'].errors [u'This field is required.'] <<< f['subject'].errors [] <<< f['e-mail'].errors [] Cada instancia Form ligada tiene un atributo errors que proporciona un diccionario que asigna nombres de campos a listas de mensajes de error: <<< f = ContactForm({subject: Hello, message: }) <<< f.errors {message: [u'This field is required.']} Por ltimo, para los casos de instancias de formulario cuyos datos se ha encontrado ser vlidos, est disponible el atributo cleaned_data. Este es un diccionario de los datos emitidos, limpiado. El marco de formularios de Django, no slo valida los datos, sino que los limpia para convertir de valores a los tipos de Python adecuados, como se muestra aqu: <<< f = ContactForm({subject: Hello, e-mail: adrian@example.com, message: Nice site!}) <<< f.is_valid() True <<< f.cleaned_data {message: uNice site!, e-mail: uadrian@example.com, subject: uHello} Nuestro formulario de contacto trata slo con cadenas, que son limpiadas a objetos Unicode, pero si tuviramos que utilizar un IntegerField o un DateField, el marco de formularios garantizara que cleaned_data utiliza enteros Python adecuados u objetos datetime.date para los campos dados.

Vincular objetos Form en vistas


Ahora que tiene algunos conocimientos bsicos sobre las clases Form, veremos cmo podemos utilizar esta infraestructura para sustituir algo en nuestra vista contact(). He aqu cmo podemos reescribir contacto() para utilizar el marco de formularios: # views.py from django.shortcuts import render_to_response from mysite.contact.forms import ContactForm def contact(request):

if request.method == POST: form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail( cd['subject'], cd['message'], cd.get(e-mail, noreply@example.com), ['siteowner@example.com'], ) return HttpResponseRedirect(/contact/thanks/) else: form = ContactForm() return render_to_response(contact_form.html, {form: form}) # contact_form.html <html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if form.errors %} <p style=color: red;> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form action=" method=post> <table> {{ form.as_table }} </table> <input type=submit value=Submit>

</form> </body> </html> El marco de formularios de Django gestiona la pantalla del HTML, la validacin, la limpieza de los datos, y el volver a mostrar el formulario con errores. Trate de ejecutar esto en local. Cargue el formulario, emtalo sin rellenar ningun campo, emtalo con una direccin invlida de correo electrnico, y finalmente emtalo con los datos vlidos.

Cambiar como se renderizan los campos


Probablemente lo primero que notar cuando renderiza el formulario localmente es que el campo mensaje se muestra como un <input type=text>, y debera ser un <textarea>. Podemos arreglar esto mediante el establecimiento del widget del campo: from django import forms class ContactForm(forms.Form): subject = forms.CharField() e-mail = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea El marco de formularios separa la lgica de presentacin de cada campo en un conjunto de widgets. Cada tipo de campo tiene un widget por defecto, pero se puede reemplazar la configuracin predeterminada o proporcionar un widget personalizado. Piense en las clases Field como la representacin de la lgica de validacin, mientras que los widgets representan la lgica de presentacin.

Establecer una longitud mxima


Una de las necesidades de validacin ms comn es comprobar que un campo es de un tamao determinado.Mejoremos nuestro formulario de contacto limitando el asunto a 100 caracteres. Para hacer eso, proporcionar un max_length al Charfield, de esta forma: from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) e-mail = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) Un argumento opcional min_length tambin est disponible.

Establecer valores iniciales

Como una mejora a este formulario, vamos a aadir un valor inicial para el campo Asunto: I love your site! . Para hacer esto, podemos utilizar el argumento initial cuando creamos una instancia Form: def contact(request): if request.method == POST: form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail( cd['subject'], cd['message'], cd.get(e-mail, noreply@example.com), ['siteowner@example.com'], ) return HttpResponseRedirect(/contact/thanks/) else: form = ContactForm(initial={subject: I love your site!}) return render_to_response(contact_form.html, {form: form}) Tenga en cuenta que hay una diferencia entre pasar datos inicialmente y pasar datos que se ligan al formulario. Si slo pasa los datos iniciales, el formulario ser independiente, lo que significa que no tendr ningn mensaje de error.

Aadir reglas de validacin personalizadas


Decidimos adoptar una nueva poltica de validacin: cuatro palabras o ms, por favor. Hay varias maneras de conectar la validacin personalizada a un formulario Django. Si nuestra regla es algo que volver a utilizar una y otra vez, podemos crear un tipo de campo personalizado. La mayora de las validaciones personalizadas son asuntos de una sola vez, sin embargo, y puede vincularse directamente a la clase Form. Queremos validacin adicional en el campo del mensaje, por lo que aadimos un mtodo clean_message() a nuestra clase Form: from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) e-mail = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea)

def clean_message(self): message = self.cleaned_data['message'] num_words = len(message.split()) if num_words < 4: raise forms.ValidationError(Not enough words!) return message El sistema de formularios de Django busca automticamente cualquier mtodo cuyo nombre empieza con clean_ y termina con el nombre de un campo. Si existe alguno, se llama durante la validacin. En concreto, el mtodo clean_message() ser llamado despus de la lgica de validacin por defecto para un campo determinado (en este caso, la lgica de validacin para un CharField obligatorio).Debido a que los datos del campo ya han sido parcialmente procesados, hay que sacarlos de self.cleaned_data. Adems, no tiene que preocuparse de comprobar que el valor existe y no es vaco, el validador lo hace de forma predeterminada. Nosotros, utilizamos una combinacin de len() y split() para contar el nmero de palabras. Si el usuario ha introducido muy pocas palabras, lanzamos un forms.ValidationError. La cadena adjunta a la excepcin se muestra al usuario como un elemento de la lista de errores. Es importante que devolvamos explcitamente el valor limpiado para el campo al final del mtodo. Esto nos permite modificar el valor (o convertirlo a un tipo diferente de Python) dentro de nuestro mtodo de validacin personalizado. Si olvidamos de la instruccin de retorno, entonces ser devuelto None y el valor original se perder.

Especificar etiquetas
Por defecto, las etiquetas del formulario HTML autogenerado por Django se crean mediante la sustitucin de los guiones bajos por espacios y capitalizando la primera letra, por lo que la etiqueta para el campo e-mail es E-mail. Suena familiar? Es el mismo algoritmo simple que los modelos Django utilizan para calcular los valores verbose_name de los campos por defecto. Pero, como con los modelos Django, podemos personalizar la etiqueta de un campo determinado. Slo tiene que utilizar la etiqueta, de este modo: class ContactForm(forms.Form): subject = forms.CharField(max_length=100) e-mail = forms.EmailField(required=False, label=Your e-mail address) message = forms.CharField(widget=forms.Textarea)

Personalizar el diseo de los formularios

Nuestra plantilla contact_form.html usa {{ form.as_table }} para mostrar el formulario, pero podemos visualizarlo de otras formas para conseguir un control ms detallado sobre la pantalla.
T T

La forma ms rpida para personalizar la presentacin de los formularios es con CSS. Las listas de error, en particular, podan realizarse con algunas mejoras visuales, y las listas de error autogeneradas usan <ul class = errorlist> precisamente para que se pueda apuntar a ellas con CSS. El siguiente CSS hace realmente que nuestros errores destaquen: <style type=text/css> ul.errorlist { margin: 0; padding: 0; } .errorlist li { background-color: red; color: white; display: block; font-size: 10px; margin: 0 0 3px; padding: 4px 5px; } </style> Aunque es conveniente disponer de nuestro HTML de formulario generado para nosotros, en muchos casos, usted desear reemplazar la representacin por defecto. Cada widget de campo (<input type=text>, <select>, <textarea>, etc) pueden ser renderizado individualmente mediante el acceso a {{ form.fieldname }} en la plantilla, y los errores asociados con un campo estn disponibles como {{ form.fieldname.errors }}. Con esto en mente, podemos construir una plantilla personalizada para nuestro formulario de contacto con el siguiente cdigo de plantilla: <html> <head> <title>Contact us</title> </head> <body>

<h1>Contact us</h1> {% if form.errors %} <p style=color: red;> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form action=" method=post> <div class=field> {{ form.subject.errors }} <label for=id_subject>Subject:</label> {{ form.subject }} </div> <div class=field> {{ form.e-mail.errors }} <label for=id_e-mail>Your e-mail address:</label> {{ form.e-mail }} </div> <div class=field> {{ form.message.errors }} <label for=id_message>Message:</label> {{ form.message }} </div> <input type=submit value=Submit> </form> </body> </html> {{ form.message.errors }} muestra una <ul class=errorlist> si hay errores y una cadena en blanco si el campo es vlido (o el formulario no est ligado). Tambin puede tratar form.message.errors como un valor booleano o incluso iterar sobre l como una lista. Considere este ejemplo: <div class=field{% if form.message.errors %} errors{% endif %}>

{% if form.message.errors %} <ul> {% for error in form.message.errors %} <li><strong>{{ error }}</strong></li> {% endfor %} </ul> {% endif %} <label for=id_message>Message:</label> {{ form.message }} </div> En el caso de errores de validacin, esto aadir una clase errors al <div> y muestra la lista de errores en una lista desordenada.

Tutorial de Django VII


HTU UTH

19. agosto 2010 - Visitada 1167 veces, 1 hoy Tcnico


HTU UTH

Vistas y URLconfs avanzadas


TU UT

Trucos URLconf
No hay nada especial en URLconfs como todo en Django, slo cdigo Python. Racionalizar las importaciones de funciones Considerar la siguiente URLconf, basada en un ejemplo visto anteriormente:

from django.conf.urls.defaults import * from mysite.views import hello, current_datetime, hours_ahead urlpatterns = patterns(, (r^hello/$, hello), (r^time/$, current_datetime), (r^time/plus/(\d{1,2})/$, hours_ahead), ) Cada entrada en la URLconf incluye su vista asociada, pasada directamente como un objeto de funcin. Esto significa que es necesario importar la vista al prinicipio del mdulo. Pero, cuando una aplicacin de Django crece en complejidad, su URLconf tambin crece, y gestionar esas importaciones puede ser tedioso. (Para cada nueva vista, usted tendra que recordar importarla, y la declaracin de importacin tiende a ser demasiado larga si se utiliza este enfoque.) Es posible evitar esto con la importacin de propio mdulo views. Este ejemplo de URLconf es equivalente al anterior: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^hello/$, views.hello), (r^time/$, views.current_datetime), (r^time/plus/(d{1,2})/$, views.hours_ahead), ) Django ofrece otra manera de especificar la vista de un patrn particular en el URLconf: se puede pasar una cadena que contenga el nombre del mdulo y el nombre de la vista en lugar del objeto de funcin en s mismo. Continuando con el ejemplo en curso: from django.conf.urls.defaults import * urlpatterns = patterns(, (r^hello/$, mysite.views.hello), (r^time/$, mysite.views.current_datetime), (r^time/plus/(d{1,2})/$, mysite.views.hours_ahead), ) Notar las comillas que delimitan los nombres de las vistas.

Usando esta tcnica, ya no es necesario importar las vistas; Django automticamente importa la funcin de vista apropiada la primera vez que se necesita, segn la cadena que describe el nombre y la ruta de la funcin de vista. Una abreviatura ms que usted puede usar cuando utiliza esta tcnica es factorizar un prefijo de vista comn. En nuestro ejemplo de URLconf, cada una de las cadenas de vista comienza con mysite.views. Podemos factorizar este prefijo comn y pasarlo como el primer argumento a los patrones, as: from django.conf.urls.defaults import * urlpatterns = patterns(mysite.views, (r^hello/$, hello), (r^time/$, current_datetime), (r^time/plus/(d{1,2})/$, hours_ahead), ) Con estos dos enfoques en mente, cul es mejor? Realmente depende de su estilo personal de programacin y de sus necesidades. Las ventajas de la cadena son las siguientes:

Es ms compacto, porque no es necesario importar las funciones de vista. El resultado es URLconfs ms legibles y manejables si las funciones de su vista se reparten entre diferentes mdulos de Python.

Las ventajas del enfoque de objeto de funcin son las siguientes:


Se permite un fcil ajuste de las funciones de vista. Es ms acorde con las tradiciones de Python, como pasar funciones como objetos.

Ambos enfoques son vlidos, e incluso se pueden mezclar en el mismo URLconf. La eleccin es suya.

Usar varios Prefijos de Vista


En la prctica, si utiliza la tcnica de cadena, probablemente acabe mezclando vistas que no tienen un prefijo comn. Sin embargo, usted an puede usar la abreviatura del prefijo de vistas para eliminar la duplicacin. Slo tiene que aadir varios objetos patterns() juntos, as: from django.conf.urls.defaults import * urlpatterns = patterns(mysite.views, (r^hello/$, hello), (r^time/$, current_datetime), (r^time/plus/(\d{1,2})/$, hours_ahead),

) urlpatterns += patterns(weblog.views, (r^tag/(\w+)/$, tag), )

URLs especiales en modo Debug


Hablando de la construccin de urlpatterns de forma dinmica, es posible que desee tomar ventaja de esta tcnica alterando el comportamiento de su URLconf en el modo de depuracin de Django. Para ello, basta con comprobar el valor de la propiedad DEBUG en tiempo de ejecucin, as: from django.conf import settings from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^$, views.homepage), (r^(\d{4})/([a-z]{3})/$, views.archive_month), ) if settings.DEBUG: urlpatterns += patterns(, (r^debuginfo/$, views.debug), ) En este ejemplo, la URL /debuginfo/ estar disponible slo si la propiedad DEBUG es True.

Uso de Grupos con nombre


En todos nuestros ejemplos de URLconf hasta ahora, hemos usado, grupos de expresiones regulares sin nombre, es decir, ponemos entre parntesis las partes de la URL que queremos capturar y, Django pasa ese texto capturado a la funcin de vista como un argumento posicional. En un uso ms avanzado, es posible utilizar grupos con nombre de expresiones regulares para capturar los bits de la URL y pasarlos como argumentos de palabra clave a una vista. En las expresiones regulares Python, la sintaxis para grupos con nombre de expresiones regulares es (?Ppattern), donde name es el nombre del grupo y pattern es un patrn de concordancia.

He aqu un ejemplo de URLconf que usa grupos sin nombre: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^articles/(\d{4})/$, views.year_archive), (r^articles/(\d{4})/(\d{2})/$, views.month_archive), ) Aqu, la misma URLConf reescrita, usando grupos con nombre: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^articles/(?P\d{4})/$, views.year_archive), (r^articles/(?P\d{4})/(?P\d{2})/$, views.month_archive), ) Esto logra exactamente lo mismo que el ejemplo anterior, con una sutil diferencia: los valores capturados se pasan a las funciones de vista como argumentos de palabras clave en lugar de argumentos posicionales. Por ejemplo, con grupos sin nombre, una peticin a /articles/2006/03/ dara lugar a una llamada a la funcin equivalente a esto: month_archive(request, 2006, 03) Con grupos con nombre, la misma peticin resultara en esta llamada a funcin: month_archive(request, year=2006, month=03) En la prctica, usar grupos con nombre hace a su URLconfs un poco ms explcita y menos propensa a los errores del orden de los argumentos y puede volver a ordenar los argumentos de la funcin sus definiciones de vistas. Siguiendo el ejemplo anterior, si quisieramos cambiar la URL para incluir el mes antes del ao, y estamos utilizando grupos sin nombre, tendramos que recordar cambiar el orden de los argumentos en la vista month_archive. Si estuviramos utilizando grupos con nombre, cambiar el orden de los parmetros capturados en la URL no tendra ningn efecto en la vista. Por supuesto, los beneficios de los grupos con nombre llegan a costa de la brevedad; algunos desarrolladores encuentran la sintaxis de un grupo con nombre fea y demasiado detallada. Sin embargo, otra de las ventajas de los grupos con nombre es la legibilidad, especialmente para aquellos que no estn ntimamente familiarizados con expresiones

regulares o su aplicacin de Django particular. Es ms fcil ver lo que sucede, de un vistazo, en una URLconf que utiliza grupos con nombre.

Comprender el algoritmo de agrupacin/concordancia


Una advertencia con el uso de grupos con nombre en una URLconf es que un nico patrn de URLconf no puede contener tanto grupos con nombre como sin nombre. Si usted hace esto, Django no dar ningn error, pero usted probablemente encontrar que sus URLs no son coincidentes tal y como usted espera. En concreto, aqu est el algoritmo que sigue el analizador URLconf:

Si hay algunos argumentos con nombre, utilizar esos, haciendo caso omiso de los argumentos con nombre. De lo contrario, pasar todos los argumentos sin nombre como argumentos posicionales. En ambos casos, pasar opciones adicionales como argumentos de palabra clave.

Pasar opciones extra a funciones de vista


A veces usted se encontrar con la escritura de funciones de vista que son bastante similares, con slo unas pequeas diferencias. Por ejemplo, supongamos que tiene dos vistas cuyos contenidos son idnticos, excepto por las plantillas que utilizan: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^foo/$, views.foo_view), (r^bar/$, views.bar_view), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foo_view(request): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template1.html, {m_list: m_list}) def bar_view(request): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template2.html, {m_list: m_list}) Estamos repitiendo el cdigo, y eso es poco elegante. En principio, usted puede pensar eliminar la redundancia utilizando el mismo punto de vista, tanto para las direcciones

URL, poniendo entre parntesis la URL a capturar, y comprobar la URL dentro de la vista para determinar la plantilla, as: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^(foo)/$, views.foobar_view), (r^(bar)/$, views.foobar_view), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, url): m_list = MyModel.objects.filter(is_new=True) if url == foo: template_name = template1.html elif url == bar: template_name = template2.html return render_to_response(template_name, {m_list: m_list}) El problema con esta solucin, sin embargo, es que acopla las URL a su cdigo. Si usted decide cambiar el nombre /foo/ a /fooey/, tendr que acordarse de cambiar el cdigo de la vista. La solucin elegante implica un parmetro URLconf opcional. Cada patrn en una URLconf puede incluir un tercer elemento: un diccionario de los argumentos de palabra clave para pasar a la funcin de vista. Con esto en mente, podemos volver a escribir nuestro ejemplo actual de esta manera: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^foo/$, views.foobar_view, {template_name: template1.html}), (r^bar/$, views.foobar_view, {template_name: template2.html}), )

# views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {m_list: m_list}) Esta tcnica de opciones URLconf extra es una buena forma de enviar informacin adicional a las funciones de la vista con una sobrecarga mnimo. Las siguientes secciones contienen un par de ideas sobre cmo utilizar la tcnica de opciones de URLconf extra en sus propios proyectos.

Fingiendo valores URLConf capturados


Digamos que tiene un conjunto de vistas que coinciden con un patrn, junto con otra URL que no se ajusta a ese patrn, pero cuya lgica de la vista es la misma. En este caso, puede falsear la captacin de valores URL mediante el uso de opciones URLconf extra para manejar esa URL adicional con la misma vista. Por ejemplo, usted podra tener una aplicacin que muestre algunos datos de un da en particular, con direcciones de Internet tales como las siguientes: /mydata/jan/01/ /mydata/jan/02/ /mydata/jan/03/ # /mydata/dec/30/ /mydata/dec/31/ Esto es bastante simple usted puede capturarlos con una URLconf como esta (con sintaxis de grupos con nombre): urlpatterns = patterns(, (r^mydata/(?P\w{3})/(?P\d\d)/$, views.my_view), ) Y la funcin de vista sera as: def my_view(request, month, day): # . Ese mtodo es sencillo no es nada que no haya visto antes. El truco viene cuando se quiere aadir otra URL que utiliza my_view pero cuya URL no incluye un mes y/o da.

Por ejemplo, usted podra querer agregar otra URL, /mydata/birthday/, que sera equivalente a /mydata/jan/06/ : urlpatterns = patterns(, (r^mydata/birthday/$, views.my_view, {month: jan, day: 06}), (r^mydata/(?P\w{3})/(?P\d\d)/$, views.my_view), ) Usted no tiene que cambiar su funcin de vista en absoluto.

Hacer una vista genrica


Es buena prctica de programacin factorizar puntos comunes en el cdigo. Por ejemplo, con estas dos funciones de Python: def say_hello(person_name): print Hello, %s % person_name def say_goodbye(person_name): print Goodbye, %s % person_name podemos factorizarlas usando un parmetro: def greet(person_name, greeting): print %s, %s % (greeting, person_name) Podemos aplicar esta misma filosofa a las vista Django usando parmetros adicionales URLconf. Con esto en mente, usted puede comenzar a hacer abstracciones de alto nivel de sus vistas. En lugar de pensar: Esta vista muestra una lista de objetos Event, y Esta vista muestra una lista de objetos BlogEntry, dese cuenta que ambos son casos especficos de vista que muestra una lista de objetos, donde el tipo de objeto es variable. Tome este cdigo, por ejemplo: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^events/$, views.event_list), (r^blog/entries/$, views.entry_list), )

# views.py from django.shortcuts import render_to_response from mysite.models import Event, BlogEntry def event_list(request): obj_list = Event.objects.all() return render_to_response(mysite/event_list.html, {event_list: obj_list}) def entry_list(request): obj_list = BlogEntry.objects.all() return render_to_response(mysite/blogentry_list.html,{entry_list: obj_list}) Las dos vistas hacen esencialmente lo mismo: mostrar una lista de objetos. Factoricemos el tipo de objeto que estamos mostrando: # urls.py from django.conf.urls.defaults import * from mysite import models, views urlpatterns = patterns(, (r^events/$, views.object_list, {model: models.Event}), (r^blog/entries/$, views.object_list, {model: models.BlogEntry}), ) # views.py from django.shortcuts import render_to_response def object_list(request, model): obj_list = model.objects.all() template_name = mysite/%s_list.html % model.__name__.lower() return render_to_response(template_name, {object_list: obj_list}) Con estos pequeos cambios, de repente tenemos una vista reutilizable, independiente del modelo. A partir de ahora, cada vez que necesitemos una vista que muestre un conjunto de objetos, podemos simplemente volver a utilizar esta vista object_list. Un par de apuntes de lo realizado:

Pasamos las clases del modelo directamente, como el parmetro model. El diccionario de opciones URLConf extra puede pasar cualquier tipo de objeto no slo cadenas. Usamos model.__name__.lower () para determinar el nombre de la plantilla. Cada clase Python tiene un atributo __name__ que devuelve el nombre de la clase. Esta funcin es til en momentos como ste, cuando no sabemos el tipo de clase hasta el tiempo de ejecucin.

Pasamos el nombre de variable genrico object_list a la plantilla. Fcilmente podramos cambiar este nombre a blogentry_list o event_list.

Dado que los sitios web de bases de datos tienen varios patrones comunes, Django viene con un conjunto de vistas genricas que utilizan esta tcnica para ahorrar tiempo.

Dar opciones de configuracin de vista


Si est desarrollando una aplicacin Django, lo ms probable es que los usuarios quieran algn grado de configuracin. En este caso, es una buena idea aadir ganchos a sus vistas para las opciones de configuracin que crea que la gente puede cambiar. Puede utilizar parmetros URLConf adicionales para este propsito. Un parte comn de una aplicacin para configurar es el nombre de la plantilla: def my_view(request, template_name): var = do_something() return render_to_response(template_name, {var: var})

Comprender la precedencia de los valores capturados frente a las opciones extra


Cuando hay un conflicto, los parmetros URLconf extra tienen prioridad sobre los parmetros de captura. En otras palabras, si su URLconf captura una variable de un grupo con nombre y un parmetro URLconf extra incluye una variable con el mismo nombre, el valor del parmetro URLconf extra ser utilizado. Por ejemplo, considere esta URLconf: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^mydata/(?P\d+)/$, views.my_view, {id: 3}), ) Aqu, tanto la expresin regular como el diccionario extra incluyen un id. Cualquier peticin (por ejemplo, /mydata/2/ o /mydata/432432/) ser tratada como si id es 3, con independencia del valor capturado en la URL. Notamos esto slo para ayudarle a evitar caer en el error.

Usar argumentos de vista por defecto


Otro truco conveniente es especificar los parmetros por defecto para los argumentos de una vista. Esto le dice a la vista que valor usar porn defecto para un parmetro si no se especifica ninguno. He aqu un ejemplo:

# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^blog/$, views.page), (r^blog/page(?P\d+)/$, views.page), ) # views.py def page(request, num=1): # Output the appropriate page of blog entries, according to num. # Aqu, ambas URLpatterns apuntan a la misma vista views.page, pero el primer patrn no captura cualquier cosa desde la URL. Si el primer patrn concuerda, la funcin page() usar su argumento predeterminado para num, 1. Si el segundo patrn concuerda, page() utilizar cualquier valor num capturado por la expresin regular.
T T

Es comn el uso de esta tcnica en relacin con las opciones de configuracin, como se explic anteriormente. En el siguiente ejemplo se hace una ligera mejora con el ejemplo de la seccin Dar opciones de configuracin de vista, proporcionando un valor predeterminado para template_name:
T T

def my_view(request, template_name=mysite/my_view.html): var = do_something() return render_to_response(template_name, {var: var})

Vistas de casos especiales


A veces usted tiene un patrn en su URLconf que maneja un gran conjunto de direcciones URL, pero usted necesitar un caso especial de ellas. En este caso, aprovechar la manera lineal en que trabaja una URLconf y colocar el caso particular en primer lugar. Por ejemplo, usted puede pensar en pginas de agregar un objeto en el sitio de administracin de Django, representado por un URLpattern as: urlpatterns = patterns(, # (^([^/]+)/([^/]+)/add/$, views.add_stage), # )

Esto coincide con las URL como /myblog/entries/add/ y /auth/groups/add/. Sin embargo, la pgina Aadir para un objeto de usuario (/auth/user/add/) es un caso especial que no muestra todos los campos del formulario, muestra dos campos de contrasea, etc. Podramos resolver este problema mediante el caso especial en la vista, de este modo: def add_stage(request, app_label, model_name): if app_label == auth and model_name == user: # do special-case code else: # do normal code pero eso es poco elegante por la razn que hemos visto varias veces en este captulo: pone lgica de URL en la vista. Como una solucin ms elegante, podemos aprovechar el hecho de que las URLconfs se procesan en orden de arriba a abajo: urlpatterns = patterns(, # (^auth/user/add/$, views.user_add_stage), (^([^/]+)/([^/]+)/add/$, views.add_stage), # ) Ahora, una peticin a /auth/user/add/ ser manejada por la vista user_add_stage. A pesar de que la URL coincide con el segundo patrn, coincide con el de arriba primero.

Capturar texto en las URLs


Cada argumento capturado es enviado a la vista como una simple cadena Unicode de Python, independientemente del orden de concordancia que la expresin regular hace. Por ejemplo, en esta lnea URLconf, el argumento year para views.year_archive() ser una cadena, no un entero, incluso aunque \d{4} slo concuerde con cadenas de enteros: (r^articles/(?P\d{4})/$, views.year_archive), Esto es importante tenerlo en cuenta cuando se est escribiendo el cdigo de la vista. Muchas funciones Python slo aceptann objetos de cierto tipo. Un error comn es tratar de crear un objeto datetime.date con valores de cadena en lugar de valores enteros valores: >>> import datetime >>> datetime.date(1993, 7, 9) Traceback (most recent call last):

TypeError: an integer is required >>> datetime.date(1993, 7, 9) datetime.date(1993, 7, 9) Trasladado a una URLConf y vista, el error se parecera a esto: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, (r^articles/(\d{4})/(\d{2})/(\d{2})/$, views.day_archive), ) # views.py import datetime def day_archive(request, year, month, day): # The following statement raises a TypeError! date = datetime.date(year, month, day) En lugar de esto, day_archive() podra escribirse correctamente as: def day_archive(request, year, month, day): date = datetime.date(int(year), int(month), int(day)) Tenga en cuenta que int () eleva un ValueError al pasar una cadena que no est compuesto exclusivamente de dgitos, pero estamos evitando el error en este caso porque la expresin regular en nuestra URLconf asegura que slo se pase cadenas que contienen dgitos a la funcin de vista.

Determinar contra qu busca la URLConf


Cuando una peticin llega, Django intenta hacer coincidir los patrones de la URLConf contra la URL solicitada, como una cadena de Python. Esto no incluye los parmetros GET o POST, o el nombre de dominio. Tampoco incluye la barra principal, ya que cada direccin tiene una barra principal. Por ejemplo, en una solicitud de http://www.example.com/myapp/, Django tratar de satisfacer myapp/. En una solicitud de http://www.example.com/myapp/?page=3, Django tratar de satisfacer myapp/. El mtodo de peticin (por ejemplo, POST, GET) no se tiene en cuenta a la hora de tratar con el URLconf. En otras palabras, todos los mtodos de peticin sern enviados a la misma funcin para la misma URL. Es la responsabilidad de una funcin de vista llevar a cabo la ramificacin basada en el mtodo de la solicitud.

Abstracciones de alto nivel de las funciones de vista


Hablando de ramificacin basada en el mtodo de la peticin, vamos a echar un vistazo a cmo podramos construir una buena manera de hacerlo. Considerar este diseo URLconf/Vista: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, # (r^somepage/$, views.some_page), # ) # views.py from django.http import Http404, HttpResponseRedirect from django.shortcuts import render_to_response def some_page(request): if request.method == POST: do_something_for_post() return HttpResponseRedirect(/someurl/) elif request.method == GET: do_something_for_get() return render_to_response(page.html) else: raise Http404() En este ejemplo, el manejo de la vista some_page() de las peticiones POST y GET es muy diferente. Lo nico que tienen en comn es una URL compartida URL: /somepage/. Como tal, es una falta de elegancia hacer frente tanto a POST y GET en la misma funcin de vista. Sera bueno si pudiramos tener dos funciones de vista separadas una que gestione las peticiones GET y otra que gestione las POST y garantizar que cada una se invoque slo cuando sea necesario. Podemos hacer eso escribiendo una funcin de vista que delege a otras vistas, ya sea antes o despus de ejecutar alguna lgica personalizada. He aqu un ejemplo de cmo esta tcnica podra ayudar a simplificar nuestra vista some_page():

# views.py from django.http import Http404, HttpResponseRedirect from django.shortcuts import render_to_response def method_splitter(request, GET=None, POST=None): if request.method == GET and GET is not None: return GET(request) elif request.method == POST and POST is not None: return POST(request) raise Http404 def some_page_get(request): assert request.method == GET do_something_for_get() return render_to_response(page.html) def some_page_post(request): assert request.method == POST do_something_for_post() return HttpResponseRedirect(/someurl/) # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns(, # (r^somepage/$, views.method_splitter, {GET: views.some_page_get, POST: views.some_page_post}), # ) Veamos que hace esto:

Escribimos una nueva vista, method_splitter(), que delega a otras vistas segn request.method. Busca dos argumentos de palabra clave, GET y POST, que deben ser funciones de vista. Si request.method es GET, llama a la vista GET. Si request.method es POST, llama a la vista POST. Si request.method es otra cosa (HEAD, etc), o si GET o POST no fueron suministrados a la funcin, se eleva un Http404.

En el URLconf, apuntamos /somepage/ al method_splitter() y le pasarmos argumentos extra las funciones para el uso de GET y POST, respectivamente. Por ltimo, dividimos la vista some_page() vista en dos funciones de vista: some_page_get() y some_page_post (). Esto es mucho mejor que colocar toda la lgica en una sola vista.

Ahora tenemos una bonita funcin de vista genrica que encapsula la lgica de delegar una vista mediante request.method. Nada de method_splitter() est ligado a nuestra aplicacin especfica, por supuesto, asi que podemos reutilizarla en otros proyectos. Pero hay una forma de mejorar el method_splitter(). Ahora, se asume que las vistas GET y POST no toman otros argumentos que request. Qu pasa si se quiere utilizar method_splitter() con vistas que, por ejemplo, capturen texto de URLs o tomen argumentos de palabra clave opcionales? Para ello, podemos usar una caracterstica agradable de Python: argumentos variables con asteriscos. Vamos a mostrar el ejemplo primero y luego explicarlo: def method_splitter(request, *args, **kwargs): get_view = kwargs.pop(GET, None) post_view = kwargs.pop(POST, None) if request.method == GET and get_view is not None: return get_view(request, *args, **kwargs) elif request.method == POST and post_view is not None: return post_view(request, *args, **kwargs) raise Http404 Aqu, refactorizamos method_splitter() para eliminar los argumentos de palabra clave GET y POST en favor de *args y **kwargs. Esta es una caracterstica Python que permite a una funcin aceptar un nmero arbitrario dinmico de argumentos cuyos nombres no se conocen hasta el tiempo de ejecucin. Si coloca un asterisco delante de un parmetro en una definicin de la funcin, cualquier argumento posicional a esa funcin se guarda en una sola tupla. Si coloca dos asteriscos delante de un parmetro en una definicin de la funcin, cualquier argumento de palabras clave para esa funcin se guardar en un diccionario nico. Por ejemplo, tenga en cuenta esta funcin: def foo(*args, **kwargs): print Positional arguments are: print args print Keyword arguments are: print kwargs

As es como funcionara: >>> foo(1, 2, 3) Positional arguments are: (1, 2, 3) Keyword arguments are: {} >>> foo(1, 2, name=Adrian, framework=Django) Positional arguments are: (1, 2) Keyword arguments are: {framework: Django, name: Adrian} Llevando esto a method_splitter(), se puede ver que estamos usando *args y **kwargs para aceptar argumentos a la funcin y distribuirlos a la vista apropiada. Pero antes de hacer eso, hacemos dos llamadas a kwargs.pop() para obtener los argumentos GET y POST, si estn disponibles. (Estamos usando pop() con un valor por defecto None para evitar KeyError si alguno no est definido.)

Envolviendo funciones de vista


Nuestro truco de vista final se basa en una avanzada tcnica de Python. Supongamos que se encuentre un montn de cdigo repetitivo a travs de diversas vistas, como en este ejemplo: def my_view1(request): if not request.user.is_authenticated(): return HttpResponseRedirect(/accounts/login/) # return render_to_response(template1.html) def my_view2(request): if not request.user.is_authenticated(): return HttpResponseRedirect(/accounts/login/) # return render_to_response(template2.html) def my_view3(request): if not request.user.is_authenticated(): return HttpResponseRedirect(/accounts/login/)

# return render_to_response(template3.html) Aqu, cada vista comienza comprobando que request.user est autenticado, es decir, que el usuario se ha validado correctamente en el sitio web y sino lo redirige a /accounts/login/. Sera bueno si pudiramos eliminar ese trozo de cdigo repetitivo de cada una de estas vistas y slo marcarlos como que requieren autenticacin. Podemos hacer esto haciendo un envoltorio de la vista. Tome un momento para estudiar esto: def requires_login(view): def new_view(request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect(/accounts/login/) return view(request, *args, **kwargs) return new_view Esta funcin, requires_login, toma una funcin de vista (view) y devuelve una nueva funcin de vista (new_view). La nueva funcin, new_view, se define dentro de requires_login y se encarga la lgica de controlar request.user.is_authenticated() y delegar a la vista original (view). Ahora, podemos eliminar las comprobaciones if not request.user.is_authenticated() de nuestras vistas y simplemente envolverlas con requires_login en nuestra URLconf: from django.conf.urls.defaults import * from mysite.views import requires_login, my_view1, my_view2, my_view3 urlpatterns = patterns(, (r^view1/$, requires_login(my_view1)), (r^view2/$, requires_login(my_view2)), (r^view3/$, requires_login(my_view3)), ) Esto tiene el mismo efecto que antes, pero con menos cdigo redundante. Ahora hemos creado una buena funcin genrica requires_login() que nos puede envolver cualquier vista para requerir un inicio de sesin.

Incluir otras URLconfs


Si desea que su cdigo sea usado en varios sitios basados en Django, debe considerar la organizacin de sus URLconfs de tal manera que se puedan incluir.

De esta forma, su URLconf puede incluir otros mdulos URLconf. Por ejemplo, esta URLconf incluye otros URLconfs: from django.conf.urls.defaults import * urlpatterns = patterns(, (r^weblog/, include(mysite.blog.urls)), (r^photos/, include(mysite.photos.urls)), (r^about/$, mysite.views.about), ) Hay un aspecto importante: las expresiones regulares en este ejemplo que apuntan a un include() no acaban en $, pero si una barra final. Cuando Django se encuentra con include(), corta parte de la URL concordante hasta ese punto y enva la cadena restante a la URLconf incluida para su posterior procesamiento. Siguiendo este ejemplo, aqu est el URLconf mysite.blog.urls: from django.conf.urls.defaults import * urlpatterns = patterns(, (r^(\d\d\d\d)/$, mysite.blog.views.year_detail), (r^(\d\d\d\d)/(\d\d)/$, mysite.blog.views.month_detail), ) Con estas dos URLconfs, aqu se muestra como se gestionaran algunas solicitudes:

/weblog/2007/: En la primera URLconf, el patrn r^weblog/ coincide. Debido a que es un include(), Django divide todo el texto coincidente, que es weblog/ en este caso. La parte restante de la direccin es 2007/, que coincide con la primera lnea en el URLconf mysite.blog.urls. /weblog//2007/ (con dos barras inclinadas): En la primera URLconf, el patrn r^weblog/ coincide. Debido a que es un include(), Django divide todo el texto coincidente, que es weblog/ en este caso. La parte restante de la direccin es /2007/, que no coincide con ninguna de las lneas en el URLconf mysite.blog.urls. /about/: Coincide con la vista mysite.views.about la primera URLconf, lo que demuestra que se pueden mezclar patrones include() con patrones no include.

Cmo trabajan con include() los parmetros capturados


Un URLconf incluido recibe cualquier parmetro capturado del URLconf padre, por ejemplo: # root urls.py from django.conf.urls.defaults import *

urlpatterns = patterns(, (r^(?P\w+)/blog/, include(foo.urls.blog)), ) # foo/urls/blog.py from django.conf.urls.defaults import * urlpatterns = patterns(, (r^$, foo.views.blog_index), (r^archive/$, foo.views.blog_archive), ) En este ejemplo, la variable username capturada se pasa al URLconf incluido y, por lo tanto, a cada funcin de vista dentro de ese URLconf. Tenga en cuenta que los parmetros capturados siempre sern pasados a todas las lneas del URLconf incluido, independientemente de si la vista de la lnea en realidad acepta esos parmetros como vlidos. Por esta razn, esta tcnica es til slo si ests seguro de que todas las vistas de la URLconf incluida aceptan los parmetros que est pasando.

Cmo trabajan con include() las opciones URLconf extras


Del mismo modo, se pueden pasar opciones adicionales URLconf a include(), tal como se pueden pasar opciones URLconf adicionales para una vista normal como un diccionario. Al hacer esto, a cada lnea de la URLconf incluida se le pasan las opciones extra. Por ejemplo, los siguientes conjuntos URLconf son funcionalmente idnticos. Conjunto uno: # urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r^blog/, include(inner), {blogid: 3}), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns(,

(r^archive/$, mysite.views.archive), (r^about/$, mysite.views.about), (r^rss/$, mysite.views.rss), ) Conjunto dos: # urls.py from django.conf.urls.defaults import * urlpatterns = patterns(, (r^blog/, include(inner)), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns(, (r^archive/$, mysite.views.archive, {blogid: 3}), (r^about/$, mysite.views.about, {blogid: 3}), (r^rss/$, mysite.views.rss, {blogid: 3}), ) Como es el caso de los parmetros capturados, las opciones adicionales siempre se pasarn a todas las lneas del URLconf incluido, independientemente de si la vista de la lnea acepta esas opciones como vlidas. Por esta razn, esta tcnica es til slo si tiene la certeza de que todas las vistas incluidas en la URLconf aceptan las opciones extra que est pasando.

You might also like