Django de un vistazo

Como Django fue desarrollado en el entorno de una redacción de noticias, fue diseñado para hacer las tareas comunes del desarrollo web rápidas y fáciles. Esta es una introducción informal de cómo escribir una aplicación basada en una base de datos con Django.

El objetivo de este documento es brindar las especificaciones técnicas suficientes para entender cómo funciona Django, pero no ser un tutorial o una referencia – ambos existen! Cuando estés listo para empezar un proyecto, podés chequear el tutorial o sumergirte en la documentación más detallada.

Diseñar tu modelo

Aunque se puede usar sin una base de datos, Django viene con un mapeador objeto-relacional a través del cual podés describir la estructura de tu base de datos en código Python.

La sintaxis de modelo de datos ofrece muchas maneras de representar tus modelos – al día de hoy ha resuelto problemas de esquema de base de datos por años. Aquí un rápido ejemplo:

mysite/news/models.py
from django.db import models

class Reporter(models.Model):
    full_name = models.CharField(max_length=70)

    def __str__(self):              # __unicode__ on Python 2
        return self.full_name

class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter)

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

Instalarlo

A continuación hay que correr la utilidad de línea de comandos de Django para crear las tablas de la base de datos automáticamente:

$ python manage.py migrate

El comando migrate revisa todos los modelos disponibles y crea las tablas en la base de datos para aquellos que todavía no existan, como así también, opcionalmente, proveer un amplio control sobre los esquemas.

Aprovecha la API ya provista

En este punto ya obtenés una completa API Python para acceder a tus datos. La API es creada “al vuelo”, sin requerir generación de código:

# Import the models we created from our "news" app
>>> from news.models import Reporter, Article

# No reporters are in the system yet.
>>> Reporter.objects.all()
[]

# Create a new Reporter.
>>> r = Reporter(full_name='John Smith')

# Save the object into the database. You have to call save() explicitly.
>>> r.save()

# Now it has an ID.
>>> r.id
1

# Now the new reporter is in the database.
>>> Reporter.objects.all()
[<Reporter: John Smith>]

# Fields are represented as attributes on the Python object.
>>> r.full_name
'John Smith'

# Django provides a rich database lookup API.
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith='John')
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains='mith')
<Reporter: John Smith>
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Reporter matching query does not exist.

# Create an article.
>>> from datetime import date
>>> a = Article(pub_date=date.today(), headline='Django is cool',
...     content='Yeah.', reporter=r)
>>> a.save()

# Now the article is in the database.
>>> Article.objects.all()
[<Article: Django is cool>]

# Article objects get API access to related Reporter objects.
>>> r = a.reporter
>>> r.full_name
'John Smith'

# And vice versa: Reporter objects get API access to Article objects.
>>> r.article_set.all()
[<Article: Django is cool>]

# The API follows relationships as far as you need, performing efficient
# JOINs for you behind the scenes.
# This finds all articles by a reporter whose name starts with "John".
>>> Article.objects.filter(reporter__full_name__startswith='John')
[<Article: Django is cool>]

# Change an object by altering its attributes and calling save().
>>> r.full_name = 'Billy Goat'
>>> r.save()

# Delete an object with delete().
>>> r.delete()

Interfaz de administración dinámica: no sólo los andamios – la casa completa

Una vez que tus modelos están definidos, Django puede crear automáticamente una interfaz de administración profesional, lista para producción – un sitio web que permite a usuarios autenticados agregar, modificar y borrar objetos. Es tan fácil como registrar tu modelo en el sitio de administración:

mysite/news/models.py
from django.db import models

class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter)
mysite/news/admin.py
from django.contrib import admin

from . import models

admin.site.register(models.Article)

La filosofía aquí es que tu sitio es editado por un staff, un cliente o quizás solamente vos – y vos no querés tener que crear las interfaces de backend solamente para manejar el contenido.

Un flujo típico al crear las apps Django es definir los modelos y configurar el sitio de administración corriendo tan rápido como sea posible, de tal forma que el staff (o los clientes) pueden empezar a agregar información. Y luego, desarrollar la manera en que esta información es presentada al público.

Diseñar tus URLs

Un esquema de URLs limpio y elegante es un detalle importante en una aplicación web de calidad. Django incentiva el diseño elegante de URLs y no añade ningún sufijo como .php or .asp.

Para diseñar las URLs de una app, hay que crear un módulo Python llamado URLconf. Es una tabla de contenidos para tu app, contiene un simple mapeo entre patrones de URL y funciones Python. Los URLconfs también sirven para desacoplar las URLs del código Python.

A continuación cómo podría ser un URLconf para el ejemplo anterior de Reporter/Article:

mysite/news/urls.py
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

El código de arriba mapea URLs, listadas como expresiones regulares simples, a la ubicación de funciones Python de callback (“views”). Las expresiones regulares usan paréntesis para “capturar” valores en las URLs. Cuando un usuario pide una página, Django recorre los patrones, en orden, y se detiene en el primero que coincide con la URL solicitada. (Si ninguno coincide, Django llama a un view especial para un 404.) Esto es muy rápido porque las expresiones regulares se compilan cuando se carga el código.

Una vez que una de las expresiones regulares coincide, Django importa e invoca la view correspondiente, que es simplemente una función Python. Cada view recibe como argumentos un objeto request – que contiene la metada del request – y los valores capturados en la expresión regular.

Por ejemplo, si el usuario solicita la URL “/articles/2005/05/39323/”, Django llamaría a la función news.views.article_detail(request, '2005', '05', '39323').

Escribir tus views

Cada view es responsable de hacer una de dos cosas: devolver un objeto HttpResponse con el contenido de la página solicitada, o levantar una excepción como Http404. El resto depende de cada uno.

Generalmente, una view obtiene datos de acuerdo a los parámetros que recibe, carga un template y lo renderiza usando esos datos. Este es un ejemplo de una view para year_archive siguiendo con el ejemplo anterior:

mysite/news/views.py
from django.shortcuts import render

from .models import Article

def year_archive(request, year):
    a_list = Article.objects.filter(pub_date__year=year)
    context = {'year': year, 'article_list': a_list}
    return render(request, 'news/year_archive.html', context)

Este ejemplo usa el sistema de templates de Django, que tiene varias características poderosas pero es lo suficientemente simple de usar para no-programadores.

Diseñar tus templates

El código anterior cargar el template news/year_archive.html.

Django tiene un path de búsqueda de templates, que permite minimizar la redundancia. En tus settings, especificá una lista de directorios para revisar por templates en DIRS. Si un template no existe en el primer directorio, se busca en el segundo, y así sucesivamente.

Supongamos que el template news/year_archive.html se encuentra, su contenido podría ser:

mysite/news/templates/news/year_archive.html
{% extends "base.html" %}

{% block title %}Articles for {{ year }}{% endblock %}

{% block content %}
<h1>Articles for {{ year }}</h1>

{% for article in article_list %}
    <p>{{ article.headline }}</p>
    <p>By {{ article.reporter.full_name }}</p>
    <p>Published {{ article.pub_date|date:"F j, Y" }}</p>
{% endfor %}
{% endblock %}

Las variables se encierran entre doble llaves. {{ article.headline }} significa “Escribir el valor del atributo headline del objeto article.” Pero los puntos no solamente se usan para atributos. También se usan para acceder a una clave de un diccionario, acceder a un índice y llamadas a función.

Notar que {{ article.pub_date|date:"F j, Y" }} usa un “pipe” (el caracter “|”) al estilo Unix. Se trata de lo que se llama un template filter, y es una manera de aplicar un filtro al valor de una variable. En este caso, el filtro date formatea un objeto datetime de Python con el formato dado (como en el caso de la función date de PHP).

Podés encadenar tantos filtros como quieras. También podés escribir filtros propios. Podés escribir template tags personalizados, que corren código Python propio detrás de escena.

Finalmente, Django usa el concepto de “herencia de templates”: eso es lo que hace {% extends "base.html" %}. Significa “Primero cargar el template llamado ‘base’, que define una serie de bloques, y rellenar esos bloques con los siguientes bloques”. En síntesis, permite recortar drásticamente la redundancia en los templates: cada template solamente tiene que definir lo que es único para él mismo.

El template “base.html”, incluyendo el uso de archivos estáticos, podría ser algo como:

mysite/templates/base.html
{% load staticfiles %}
<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <img src="{% static "images/sitelogo.png" %}" alt="Logo" />
    {% block content %}{% endblock %}
</body>
</html>

Simplificando, define el look-and-feel del sitio (con el logo del sitio) y provee los “espacios” para que los templates hijos completen. Esto hace que el rediseño de un sitio sea tan sencillo como modificar un único archivo – el template base.

También permite crear múltiple versiones de un sitio, con diferentes templates base y reusando los templates hijos. Los creadores de Django han usado esta técnica para crear completamente diferentes de sitios para su versión móvil – simplemente creando un nuevo template base.

Hay que notar que si uno prefiere puede usar un sistema de templates distinto al de Django. Si bien el sistema de templates de Django está particularmente bien integrado con la capa de Django de modelos, nada nos fuerza a usarlo. Tampoco es obligatorio usar la capa de abstracción de la base de datos provista por Django. Se puede usar otra abstracción, leer de archivos XML, leer de archivos de disco, o lo que uno quiera. Cada pieza de Django – modelos, views, templates – está desacoplada del resto.

Esto es sólo la superficie

Esta es tan sólo un rápido vistazo a la funcionalidad de Django. Algunas otras características útiles:

  • Un framework de caching que se integra con memcached y otros backends.

  • Un framework de sindicación que hace que crear feeds RSS y Atom sea tan fácil como escribir una pequeña clase Python.

  • Más y mejores características en la creación automática del sitio de administración – esta introducción apenas trata el tema superficialmente.

Los siguientes pasos obvios son bajar Django, leer el tutorial y unirse a la comunidad. Gracias por tu interés!