Aplicaciones web de alta calidad con Django (2a parte).


Su primera Página Django: Hola Mundo
Como primer objetivo, vamos a crear una página Web que produzca el mensaje de ejemplo famoso: “Hola mundo”.
 
Con Django-, el contenido de la página es producido por una vista, y la dirección se especifica en una URLconf.  En primer lugar, vamos a escribir la función de la vista “Hola Mundo”.
 
Una vista “Hola Mundo” es simple. Aquí está toda la función que debe escribir en el archivo views.py:

from django.http import HttpResponse
def hello(request):
return HttpResponse(“Hello world”)
Software Libre
Una vista en Python es sólo una función que toma un HttpRequest como su primer parámetro y devuelve una instancia de HttpResponse. Para que una función de Python sea una vista Django, tiene que hacer esas dos cosas. (Hay excepciones, pero las veremos más tarde.) Si en este momento ejecuta python manage.py runserver de nuevo, seguirás viendo el mensaje “Bienvenido a Django”, sin ningún rastro de “Hola mundo”.  Eso se debe a que el proyecto mysite no conoce la vista hello; se necesita ahora decirle a Django explícitamente 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. Básicamente, es un mapeo entre las URL y las funciones de vista que deben llamarse para esas direcciones URL. El URLconf por defecto incluye algunas características comentadas de uso común en Django, por lo que la activación de esas características es tan fácil como descomentar las líneas adecuadas. Si se ignora el código comentado, aquí está la esencia de un URLconf:

from django.conf.urls.defaults import *
urlpatterns = patterns(”,
)
Lo más importante a destacar es la variable urlpatterns, que Django espera encontrarla en el módulo URLconf. Esta variable define la asignación entre las direcciones URL y el código que controla las direcciones URL. Por defecto, el URLconf está vacío – la aplicación Django está en blanco. Para agregar una URL y una vista al URLconf, simplemente añadir una tupla Python que asigna un patrón de URL a la función de la vista. He aquí cómo 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 petición a la URL /hello/ debería ser gestionada por la función 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ó ejecutándose también está bien. El servidor de desarrollo detecta automáticamente los cambios en su código 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 dirección 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 página web en Django.
django
Una nota rápida sobre errores 404.
En este punto, el URLconf define sólo un único patrón de URL: el que trata las solicitudes de la dirección /hello/. ¿Qué sucede cuando usted solicita una dirección URL diferente?
 
Usted debe ver un mensaje de “Página no encontrada”. Django muestra este mensaje porque ha solicitado una URL que no está definida en su URLconf.
La utilidad de esta página va más allá del mensaje básico de error 404. También le dice, de forma precisa que URLconf Django es usada y cada patrón utilizado en el URLconf. De esa información, usted debe ser capaz de determinar por qué la dirección URL solicitada arrojó un error 404.
 
Naturalmente, esta información es confidencial y está destinada únicamente a usted, el desarrollador Web. Si esto fuese un sitio de desplegado en Internet, usted no desearía exponer esa información al público. Por esta razón, esta página “Página no encontrada”, se muestra sólo si su Proyecto de Django se encuentra en modo de depuración. Le explicaremos cómo desactivar el modo de depuración más tarde. Por ahora, sólo sepa que cada proyecto Django creado se encuentra en modo de depuración, y si el proyecto no está en modo de depuración, Django emite una respuesta 404 diferente.
 
Una nota rápida sobre la raíz del sitio.
Como se explicó en la última sección, verá un mensaje de error 404 si usted va a la raíz del sitio: http://127.0.0.1:8000/. El patrón URL para que coincida con la raíz del sitio es un poco contradictorio, por lo que es digno de mención. Cuando esté listo para poner en práctica una vista de la raíz del sitio, utilice el patrón de URL ‘^$’, que coincide con una cadena vacía. He aquí un ejemplo:

from mysite.views import hello, my_homepage_view
urlpatterns = patterns(”,
(‘^$’, my_homepage_view),
# …
)
Cómo Django procesa una petición:
Una petición viene a /hello/. Django determina el URLconf raíz en base a ROOT_URLCONF. Django busca en todos los urlpatterns del URLconf por el primero que coincida con /hello/. Si encuentra una coincidencia, llama a la función de vista asociada. La función de vista devuelve un HttpResponse. Django convierte el HttpResponse en la respuesta HTTP apropiada, que resulta en una página web. Ahora que conoce los aspectos básicos de cómo hacer páginas Django. Es muy sencillo, en realidad: sólo escribir funciones de vista y mapearlas a URLs a través de URLconfs.
python
Segunda vista: contenido dinámico
Vamos a crear algo más dinámico: una página 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, sólo la salida del reloj interno del servidor. Es sólo un poco más emocionante que “Hola mundo”, pero se muestran un par de conceptos nuevos.
Para realizar una vista Django que muestre la fecha y hora actuales, sólo es necesario colocar la sentencia datetime.datetime.now() en una vista y devolver un HttpResponse.

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 función de vista hello, esta debe residir en views.py.  Este es el aspecto completo de views.py:

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)
Después de añadir esto a views.py, agreguar el patrón URL a urls.py para decirle a Django que URL debe manejar esta vista. Algo como /time/ tendría sentido:

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 debería ver la fecha y hora actuales.
Linux
URLconfs y acoplamiento débil.
Ahora es un buen momento para destacar una filosofía clave detrás de URLconfs y detrás de Django en general: el principio de acoplamiento débil.  Si dos trozos de código están débilmente acoplados, los cambios realizados a uno de ellos tendrá poco o ningún efecto en el otro.
Las URLconfs de Django son un buen ejemplo de este principio en la práctica. En una aplicación Web Django, las definiciones de URL y las funciones de vista que ellas llaman están débilmente acopladas, es decir, la decisión de lo que la URL debe ser para una determinada función y la implementación de la función 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 dirección por ejemplo, para moverla de /time/ a /current-time/ podría hacer un cambio rápido en URLconf sin tener que preocuparse por la vista. Del mismo modo, si usted quisiera cambiar la función de vista que altera la lógica de alguna manera, podría hacerlo sin afectar a la URL a la que está vinculada la función.
Además, si usted quiere exponer a la actual funcionalidad de la fecha en varias URL, usted fácilmente podría hacerlo editando URLconf, sin tener que tocar el código de la vista. En este ejemplo, el current_datetime está disponible en dos URLs. Es un ejemplo artificial, pero esta técnica puede ser útil:

urlpatterns = patterns(”,
(‘^hello/$’, hello),
(‘^time/$’, current_datetime),
(‘^another-time-page/$’, current_datetime),
)
Las URLconfs y las vistas están débilmente acopladas en la acción.
Tercera vista: URLs dinámicas
En la vista current_datetime, el contenido de la página, la fecha/hora actual, es dinámica, pero la dirección (/time/) es estática. En la mayoría de aplicaciones Web dinámicas, sin embargo, una dirección URL contiene los parámetros que influyen en la salida de la página. Por ejemplo, una librería on-line podría dar a cada libro su propia URL.
Crearemos una tercera vista que muestre la fecha y hora actuales compensada por un cierto número de horas. El objetivo es diseñar un sitio para que la página /time/plus/1/ muestre la fecha y hora dentro de una hora, la página /time/plus/2/ muestra la fecha y hora dentro de dos horas, la página /time/plus/3/ muestre la fecha y hora dentrop de tres horas, y así sucesivamente.
Un principiante podría pensar en codificar una función de vista distinta para cada desplazamiento de hora, que podría 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, ¿cómo diseñar la aplicación para manejar los desplazamiento de hora arbitrarios? La clave es usar comodines de patrones URL. Como se mencionó anteriormente, un patrón URL es una expresión regular, por lo que puede utilizar el patrón de expresión regular d+ para que coincida con uno o más dígitos:

urlpatterns = patterns(”,
# … (r’^time/plus/d+/$’, hours_ahead),
# …
)
Este nuevo patrón 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 máximo de 99 horas. Esto significa que queremos permitir, números de uno o de dos dígitos, y en la sintaxis de la expresión 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 carácter r al principio de la expresión 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 línea.
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 minúscula. Se recomienda fuertemente que utilice raw string en cualquier momento si está definiendo una expresión regular en Python. A partir de ahora, todos los urlpatterns en este libro serán raw string.
Ahora que se ha designado un comodín para la dirección, usted necesita una manera de pasar esos datos de comodín a la función de vista, de modo que usted pueda utilizar una función de vista única para cualquier desplazamiento de hora arbitrario. Usted puede hacer esto colocando entre paréntesis los datos de la URLpattern que desea guardar. En el caso del ejemplo, lo que desea guardar es cualquier número que se introduzca en la URL, así que ponga paréntesis alrededor de d(1,2), de esta manera:

(r’^time/plus/(d{1,2})/$’, hours_ahead),
Usted está utilizando paréntesis 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 número de horas de desplazamiento. Aquí está la vista de código:

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 función de vista y el URLconf escrito, iniciar el servidor de desarrollo de Django (si no está ya en ejecución), y visitar http://127.0.0.1:8000/time/plus/3/ para verificar que funciona. A continuación, 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 patrón en el URLconf acepta números sólo de uno o dos dígitos; Django debería mostrar un error de “Página no encontrada” en este caso, tal y como vimos. La URL http://127.0.0.1:8000/time/plus/ (sin horas) también debería lanzar un error 404.
 
Páginas de error bonitas en Python.
Vamos a introducir deliberadamente un error de Python comentando en el archivo views.py las líneas 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 página de error con mucha información, incluido un mensaje TypeError que aparece en la parte superior: “unsupported type for timedelta hours component: unicode”
 
¿Qué pasó? Pues bien, la función de datetime.timedelta espera que el parámetro de horas que se le pase sea un número entero, y el trozo de código que convierte el desplazamiento a un número entero fue comentado. Eso provoca que datetime.timedelta lance un TypeError. Es el típico pequeño fallo que todos los programadores han cometido en algún momento.
 
El objetivo de este ejemplo es mostrar las páginas de error de Django. Tómese su tiempo para explorar la página de error y conocer la distinta información que ofrece.
La página de error de Django es capaz de mostrar más información en ciertos casos especiales, como el caso de errores de sintaxis de plantilla. Los veremos más tarde, cuando hablemos del sistema de plantillas de Django. Por el momento, descomente las líneas del offset = int (offset) para obtener la función de vista funcionando correctamente de nuevo.
Aplicaciones web de alta calidad con Django (2a parte).

Las partes restantes de esta Guia:

Aplicaciones web de alta calidad con Django (1a parte).