CONFIGURAR PYTHON, FRAMEWORK DJANGO

Tu primera aplicación Django, parte 1

Aprendamos a base de ejemplos.
A lo largo de este tutorial, revisaremos la creación de una aplicación de encuestas básica.
Esta aplicación constirá en dos partes:
  • Un sitio público que permitirá a la gente ver encuestas y votar en ellas.
  • Un sitio de administración que permitirá añadir, cambiar o eliminar encuestas.
Asumiremos que ya has instalado Django. Esto se puede verificar ejecutando el intérprete interactivo de Python y tecleando import django. Si ese comando se ejecuta exitosamente, sin errores, entonces Django está instalado.

Dónde conseguir ayuda:

Si te surgen problemas al seguir este tutorial, envía un mensaje a django-es (español), django-users (inglés) o entra al canal #django en irc.freenode.net (inglés) y trataremos de ayudarte.

Creando un proyecto

Si ésta es tu primera vez usando Django, tendrás que hacerte cargo de una configuración inicial. Esto es, necesitarás auto-generar código que define un proyecto Django -- un conjunto de configuraciones para una instancia de Django, incluyendo configuración de base de datos, opciones específicas de Django y detalles propios de tu aplicación.
Desde la línea de comandos, utiliza cd para cambiar de directorio a aquel donde quieras almacenar el código, luego ejecuta el comando django-admin.py startproject mysite. Esto creará un directorio mysiteen el directorio actual.

Permisos en Mac OS X

Si utilizas Mac OS X puede que veas el mensaje "permission denied" cuando intentes ejeucutar django-admin.py startproject. Esto se debe a que en sistemas basados en Unix como OS X un archivo debe ser marcado como "ejecutable" antes de poder ser ejecutado por un programa. Para hacer esto abre Terminal.app y navega (usando el comando cd) hasta el directorio donde django-admin.py esté instalado. Después ejecuta el comando chmod +x django-admin.py.

Nota

Evita que el proyecto tenga nombre igual a algún componente interno de Django o de Python. En particular, debes evitar usar nombres como django (que entrará en conflicto con Django mismo) o test (que causa conflictos con un paquete interno de Python).
django-admin.py debería estar en la ruta de búsqueda del sistema (system path) si instalaste Django usando python setup.py. Si no está en la ruta, lo puedes encontrar en site-packages/django/bin, donde site-packages es un directorio dentro de la instalación de Python. Considera crear un enlace simbólico hacia django-admin.py desde algún lugar en la ruta de búsqueda, por ejemplo/usr/local/bin.

¿Dónde debería estar este código?

Si tu experiencia anterior es usando PHP, probablemente estás acostumbrado a ubicar el código en la raíz de documentos del servidor web (algo como /var/www). Con Django no es así. No es una buena indea poner nada de este código en la ruta raíz del servidor web porque se corre el riesgo de que la gente pueda ser capaz de ver el código a través de la web. Eso no es bueno en términos de seguridad.
Ubica el código en algún directorio fuera de la raíz del servidor, por ejemplo en/home/mycode.
Veamos lo que creó startproject:
mysite/
    __init__.py
    manage.py
    settings.py
    urls.py
Estos archivos son:
  • __init__.py: Un archivo vacío que le dice a Python que este directorio debería ser considerado un paquete Python. (Lee más sobre paquetes en la documentación oficial de Python si eres principiante).
  • manage.py: Una utilidad de línea de comandos que te permite interactuar de distintas formas con este proyecto Django. Puedes leer todos los detalles sobre manage.py en django-admin.py y manage.py.
  • settings.py: Configuración para este proyecto Django. En Django settings puedes entender más sobre como funciona la configuración.
  • urls.py: Las URLs para este proyecto Django; una "tabla de contenidos" de tu sitio basado en Django. Puedes leer más sobre URLs en Despachador de URLs.

El servidor de desarrollo

Verifiquemos que lo anterior ha funcionado. Entra al directorio mysite y ejecuta el comando python manage.py runserver. Verás la siguiente salida en la línea de comandos:
Validating models...
0 errors found.
Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Acabas de arrancar el servidor de desarrollo de Django, un servidor web liviano escrito completamente en Python. Lo hemos incluido en Django para que puedas desarrollar de manera rápida, sin tener que vértelas con la configuración de un servidor de producción -- como Apache -- hasta que estés listo para producción.
Este es un buen momento para que recuerdes: NO uses este servidor en nada que se parezca a un entorno de producción. Su objetivo es ser usado sólo para desarrollo. (Estamos en el negocio del desarrollo de frameworks web, no de servidores web).
Ahora que el servidor está andando, visita http://127.0.0.1:8000/ usando un navegador web. Verás una página "Welcome to Django", en un agradable tono azul claro. ¡Funcionó!

Cambiando el puerto

Por defecto, el comando runserver arranca el servidor de desarrollo en el puerto 8000. Si quieres cambiar el puerto del servidor, pásalo como un argumento en la línea de comandos. Por ejemplo, este comando arranca el servidor en el puerto 8080:
python manage.py runserver 8080
Si quieres cambiar la dirección IP del servidor, pásala como argumento con el puerto. De este modo, para que el servidor escuche en todas las IPs públicas (útil si quieres mostrar tu trabajo en otros ordenadores), utiliza:
python manage.py runserver 0.0.0.0:8000
Todo lo que se necesita saber sobre el servidor de desarrollo está disponible en ladocumentación de runserver.

Configuración de la base de datos

Ahora, edita settings.py. Es un módulo Python normal con variables a nivel de módulo que representan configuraciones de Django. Modifica los siguientes valores en el elemento 'default' de DATABASES para que coincida con la configuración de tu base de datos.
  • ENGINE -- Ya sea 'django.db.backends.postgresql_psycopg2','django.db.backends.mysql' o 'django.db.backends.sqlite3'. Otros backends también están disponibles.
  • NAME -- El nombre de tu base de datos. Si estás usando SQLite la base de datos será un archivo en tu ordenador; en tal caso, NAME debería ser la ruta absoluta, incluyendo nombre de archivo, de dicho archivo. Si el archivo no existe se creará automáticamente cuando sincronices la base de datos por primera vez (ver abajo).
    Cuando especifiques la ruta, siempre utiliza barras hacia la derecha / incluso en Windows (por ejemplo: C:/homes/user/mysite/sqlite3.db).
  • USER -- El usuario de la base de datos (no usado en SQLite).
  • PASSWORD -- La contraseña de la base de datos (no usado en SQLite).
  • HOST -- La máquina donde está ubicada la base de datos. Déjalo como una cadena vacía si la base de datos está en la misma máquina física (no usado en SQLite).
Si las bases de datos son algo nuevo para ti te recomendamos usar simplemente SQLite (poniendo enENGINE 'django.db.backends.sqlite3'). SQLite viene incluido como parte de Python 2.5 y superior, así que no tendrás que instalar nada.

Nota

Si estás usando PostgreSQL o MySQL, asegúrate de haber creado una base de datos en este punto. Lo puedes hacer con el comando "CREATE DATABASE nombre_basededatos;" en el intérprete interactivo de tu base de datos.
Si estás usando SQLite no necesitas crear nada de antemano - la base de datos se creará automáticamente cuando se necesite.
Cuando estés editando settings.py, fíjate en la variable INSTALLED_APPS hacia el final del archivo. Esta variable contiene el nombre de todas las aplicaciones Django que están activadas en esta instancia de Django. Las aplicaciones pueden ser empacadas y distribuidas para ser usadas por otros proyectos.
Por defecto, INSTALLED_APPS contiene las siguientes aplicaciones, todas ellas vienen con Django:
  • django.contrib.auth -- Un sistema de autenticación.
  • django.contrib.contenttypes -- Un framework para tipos de contenidos.
  • django.contrib.sessions -- Un framework para manejar sesiones.
  • django.contrib.sites -- Un framework para manejar múltiples sitios con una única instalación Django.
Esas aplicaciones van incluidas por omisión como conveniencia para el caso común.
Cada una de esas aplicaciones hace uso de al menos una tabla de base de datos, por lo tanto necesitamos crear las tablas en la base de datos antes de poder usarlas. Para hacerlo, ejecuta el siguiente comando:
python manage.py syncdb
El comando syncdb revisa la variable INSTALLED_APPS y crea las tablas necesarias de acuerdo a la configuración de base de datos registrada en el archivo settings.py. Verás un mensaje por cada tabla quesyncdb cree, y se te preguntará si deseas crear una cuenta de superusuario para el sistema de autenticación. Hazlo.
Si estás interesado, inicia el cliente de tu base de datos y ejecuta \dt (PostgreSQL), SHOW TABLES;(MySQL), o .schema (SQLite) para mostrar las tablas que Django ha creado.

Para los minimalistas

Como ya se ha dicho, las aplicaciciones por defecto son incluidas para el caso común, pero no todos las necesitan. Si no quieres instalar alguna, simplemente comenta o elimina las líneas correspondientes de INSTALLED_APPS antes de ejecutar syncdb. El comando syncdb sólo creará las tablas para las aplicaciones listadas enINSTALLED_APPS.

Creando los modelos

Ahora que el entorno -- un "proyecto" -- está creado, estás en condiciones de comenzar con algo real.
Cada aplicación que codificas en Django consiste de un paquete Python, en algún lugar de tu ruta de búsqueda, que sigue cierta convención. Django viene con una utilidad que genera automáticamente la estructura de directorios básica de una aplicación, de forma que te puedas enfocar en escribir código en vez de estar creando directorios.

Proyectos vs. aplicaciones

¿Cuál es la diferencia entre un proyecto y una aplicación? Una aplicación es una aplicación web que hace algo -- por ejemplo, una bitácora, un registro de datos públicos o un sistema de encuestas. Un proyecto es un conjunto de aplicaciones configuradas para un sitio web particular. Un proyecto puede contener múltiples aplicaciones. Una aplicación puede pertenecer a múltiples proyectos.
En este tutorial crearemos nuestra aplicación para encuestas en el directorio mysite por simplicidad. Como consecuecia de esto, la aplicación estará acoplada con el proyecto -- o sea, el código Python en la aplicación de encuestas, va a acceder a mysite.polls. Luego en este tutorial, discutiremos la forma de desacoplar las aplicaciones para distribuirlas.
Para crear tus aplicaciones, asegúrate de estar en el directorio mysite e introduce este comando:
python manage.py startapp polls
Esto creará un directorio polls, que contiene la siguiente estructura:
polls/
    __init__.py
    models.py
    tests.py
    views.py
Esta estructura de directorios contendrá la aplicación de encuestas.
El primer paso para codificar una aplicación web en Django es definir tus modelos -- esencialmente, la estructura de la base de datos, con metadatos adicionales.

Filosofía

Un modelo es la fuente única y definitiva de información de tus datos. Contiene los campos y comportamiento esenciales de los datos que se están almacenando. Django sigue el Principio DRY (Don't Repeat Yourself -- No te repitas). El objetivo es definir el modelo de datos en un solo lugar y derivar cosas automáticamente a partir de él.
En nuestro sistema de encuestas, crearemos dos modelos: polls (encuestas) y choices (opciones). Unaencuesta contiene una pregunta y una fecha de publicación. Una opción tiene dos campos: el texto de la opción y un contador. Cada opción está asociada a una encuesta.
Estos conceptos se representan por un par de clases Python. Edita el archivo polls/models.py para que contenga algo como:
from django.db import models
class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()
El código es directo. Cada modelo está representado por una subclase de django.db.models.Model. Cada modelo tiene algunas variables de clase, que representan campos en la base de datos.
Cada campo está representado por una instancia de una clase models.Field -- por ejemplo,models.CharField para carácteres y models.DateTimeField para datetimes. De esta forma se le dice a Django qué tipo de datos contiene cada campo.
El nombre de cada instancia de models.Field (por ejemplo question o pub_date) es el nombre del campo, en un formato amigable para la base de datos. Este valor será usado en tu código Python y tu base de datos lo usará como el nombre de la columna correspondiente.
Es posible usar como primer argumento de un Field un nombre más legible. Esto se usa vía introspección en algunas partes de Django, y sirve como documentación. Si no se entrega este campo, Django usará el nombre del campo en la clase. En este ejemplo, sólo hemos definido un nombre especial paraPoll.pub_date.
Algunas clase Field tienen elementos obligatorios. Por ejemplo, CharField requiere que se le entregue un atributo max_length. Esto se usa no sólo en relación a la base de datos, sino también a la hora de hacer validaciones, como veremos luego.
Finalmente, nota que se definió una relación usando models.ForeignKey. Esto le informa a Django que cada Choice está relacionado con un Poll. Django permite todas las relaciones de base de datos típicas: muchos a uno, muchos a muchos y uno a uno.

Activando modelos

Con sólo la porción de código de modelo mostrada, Django obtiene mucha información. Por ejemplo, ahora Django es capaz de:
  • Crear un esquema de base de datos (las sentencias CREATE TABLE) para esta aplicación.
  • Crear una API de acceso a datos en Python para acceder a los objetos Poll y Choice.
Pero primero necesitamos decirle a nuestro modelo que la aplicación polls está instalada.

Filosofía

Las aplicaciones Django son "enchufables": Es posible usar una aplicación en múltiples proyectos, y es posible distribuir aplicaciones, debido a que no están atadas a una instalación Django particular.
Edita nuevamente el archivo settings.py y cambia el parámetro INSTALLED_APPS para incluir la cadena'mysite.polls'. Quedará así:
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'mysite.polls'
)
Ahora Django sabe que mysite incluye la aplicación polls. Ejecutemos otro comando:
python manage.py sql polls
Deberías ver algo similar a lo siguiente (las sentencias SQL CREATE TABLE para el sistema de encuestas):
BEGIN;
CREATE TABLE "polls_poll" (
    "id" serial NOT NULL PRIMARY KEY,
    "question" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL);
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
    "choice" varchar(200) NOT NULL,
    "votes" integer NOT NULL);
COMMIT;
Algunas notas:
  • La salida exacta variará dependiendo de la base de datos usada.
  • Los nombres de las tablas son generadas automáticamente combinando el nombre de la aplicación (polls) y el nombre en minúsculas del modelo -- poll y choice. (Este comportamiento puede ser cambiado).
  • Las claves primarias (los IDs) se agregan automáticamente (también es posible cambiar este comportamiento).
  • Por convención, Django anexa "_id" al campo de la clave foránea. Sí, puedes sobreescribir esto también.
  • La relación foránea se explicita mediante una sentencia REFERENCES.
  • El SQL generado depende de la base de datos que se está usando, de manera que los tipos de campos como auto_increment (MySQL), serial (PostgreSQL), o integer primary key(SQLite) son usados automáticamente. Lo mismo va para el uso de comillas en los nombres de campos -- por ejemplo, el uso de comillas simples o dobles. El autor de este tutorial está usando PostgreSQL, así que la salida de ejemplo corresponde a la sintaxis de PostgreSQL.
  • El comando sql de manage.py no ejecuta automáticamente el SQL en tu base de datos - sólo lo muestra en pantalla, para que veas lo que django piensa que se requiere. Si lo quieres, puedes copiar y pegar este SQL en la interfaz de tu base de datos. No obstante, como veremos pronto, Django provee una forma fácil de ingresar SQL a la base de datos.
Si te interesa, es posible ejecutar también los siguientes comandos:
  • python manage.py validate polls -- Busca errores en la construcción de tus modelos.
  • python manage.py sqlcustom polls -- Muestra las sentencias SQL definidas manualmente para la aplicación (por ejemplo, modificaciones de tablas y restricciones).
  • python manage.py sqlclear polls -- Muestra las sentencias DROP TABLE necesarias para esta aplicación, de acuerdo a las tablas que ya existen en la base de datos, si corresponde.
  • python manage.py sqlindexes polls -- Muestra la salida de las sentencias CREATE INDEXpara esta aplicación.
  • python manage.py sqlall polls -- Una combinación de todas las sentencias SQL de los comandos 'sql', 'sqlcustom', y 'sqlindexes'.
Revisar la salida de esos comandos puede ayudar a comprender lo que realmente ocurre tras bambalinas.
Ahora, ejecuta nuevamente syncdb para crear esas tablas del modelo en tu base de datos:
python manage.py syncdb
El comando syncdb ejecuta el sql de 'sqlall' en tu base de datos para todas las aplicaciones enINSTALLED_APPS que no existían ya en la base de datos. Esto crea todas las tablas, los datos iniciales y los índices para cada aplicación que se haya agregado al proyecto desde la última vez que se ejecutó syncdb.syncdb puede ser ejecutado tan frecuentemente como se desee, y sólo creará las tablas que no existan.
Lee la documentación sobre django-admin.py para saber todo lo que puede hacer la utilidad manage.py.

Jugando con la API

Ahora, usemos el intérprete interactivo de Python para jugar con la API que Django ofrece. Para invocar el intérprete, usa este comando:
python manage.py shell
Usamos este comando en vez de teclear simplemente "python", debido a que manage.py configura el entorno del proyecto por nosotros. "Configurar el entorno" implica dos cosas:
  • Agregar mysite a sys.path. Por flexibilidad, varias partes de Django se refieren a los proyectos en notación con puntos (por ejemplo 'mysite.poll.models'). Para que esto funcione, el paquetemysite debe estar en sys.path.
Ya hemos visto un ejemplo de esto: la configuración de INSTALLED_APPS es una lista de paquetes en notación con puntos.
  • La configuración de la variable de entorno DJANGO_SETTINGS_MODULE, que entrega la ruta de tu archivo settings.py.
django-admin.py.
Una vez dentro del intérprete, exploremos la API de la base de datos:
# Importamos las clases del modelo.
>>> from mysite.polls.models import Poll, Choice
# Aún no hay encuestas en el sistema.
>>> Poll.objects.all()
[]
# Creamos una nueva encuesta.
>>> from datetime import datetime>>> p = Poll(question="What's up?", pub_date=datetime.now())
# Grabamos el objeto en la base de datos. Se debe llamar
# explícitamente a save().
>>> p.save()
# Ahora tiene un ID. Notemos que esto podría mostrar "1L" en vez de "1",
# dependiendo de la base de datos que se use. No es importante; sólo
# significa que la interfaz con la base de datos prefiere
# retornar enteros como objetos long integer de Python.
>>> p.id1
# Accedemos a las columnas en la base de datos vía atributos de Python.
>>> p.question"What's up?"
>>> p.pub_date
datetime.datetime(2007, 7, 15, 12, 00, 53)
# Cambiamos los valores cambiando los atributos, luego llamamos a save().
>>> p.pub_date = datetime(2007, 4, 1, 0, 0)
>>> p.save()
# objects.all() muestra todas las encuestas en la base de datos.
>>> Poll.objects.all()
[<Poll: Poll object>]
Detengámonos un momento.  no es una representación muy útil de este objeto. Corrijamos eso editando el modelo polls (en el archivo polls/models.py) y agreguemos un método__str()__ tanto a Poll como a Choice:
class Poll(models.Model):
    # ...
    def __str__(self):
        return self.question
class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice
Es importante agregar métodos __str__() a tus modelos, no sólo por tu propia sanidad cuando trabajes con el intérprete interactivo, sino también porque la representación de los objetos se usa en el administración de Django que se genera automáticamente.
Nota que estos son métodos de Python comunes y corrientes. Agreguemos un método aparte, sólo como muestra:
import datetime# ...
class Poll(models.Model):
    # ...
    def was_published_today(self):
        return self.pub_date.date() == datetime.date.today()
Nota la adición de import datetime para referenciar al módulo estándar datetime de Python.
Volvamos al intérprete interactivo de Python ejecutando nuevamente python manage.py shell:
>>> from mysite.polls.models import Poll, Choice
# Nos aseguramos que el __str()__ agregado funciona.
>>> Poll.objects.all()
[<Poll: What's up?>]

# Django provee una rica API de búsqueda en base de datos que es
# manejada enteramente vía argumentos por clave.
>>> Poll.objects.filter(id=1)
[s up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]

# Obtenemos la encuesta del año 2007. Por supuesto, si estás
# siguiendo este tutorial en otro año, cámbialo según corresponda.
>>> Poll.objects.get(pub_date__year=2007)
s up?>
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Poll matching query does not exist.
# La búsqueda vía llave primaria es el caso más común, por lo que
# Django provee un atajo para búsquedas por llave primaria
# exacta.
# Lo siguiente es idéntico a Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
<Poll: What's up?>

# Asegurémonos que el método que agregamos funciona.
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_today()
False

# Demos a Poll un par de Choices. La llamda "create" crea
# un objeto choice nuevo, ejecuta la sentencia INSERT, agrega el
# objeto al conjunto de Choices disponibles y retorna el nuevo
# objeto Choice.
>>> p = Poll.objects.get(pk=1)
>>> p.choice_set.create(choice='Not much', votes=0)

>>> p.choice_set.create(choice='The sky', votes=0)

>>> c = p.choice_set.create(choice='Just hacking again', votes=0)

# Los objetos Choice disponen de una API para acceder a los
# objetos Poll relacionados.
>>> c.poll
s up?>
# Y viceversa: los objetos Poll tienen acceso a los objetos Choice.
>>> p.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3
# La API sigue automáticamente las relaciones hasta donde se
# requiera. Se usa doble subrayado para separar relaciones.
# Esto funciona con los niveles de profundidad que se desee.
#
# Busquemos todas las opciones para una encuesta cuya fecha de
# publicación es en 2007.
>>> Choice.objects.filter(poll__pub_date__year=2007)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# Eliminemos una de las opciones. Para esto se usa delete().
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()
Para más detalles de la API de acceso a datos, revisa nuestra Referencia de API de Base de Datos.
Cuando te sientas cómodo con la API, continúa con la parte 2 de este tutorial para obtener el sitio de administración automático de Django (próximamente).

No hay comentarios:

Publicar un comentario