Django

el web framework para perfeccionistas con límites de tiempo

Instalación

  • Se requiere Python  2.7+ para django 1.7
  • Funciona con Python 3.2+
sudo apt-get update
sudo apt-get install python-setuptools python-dev build-essential git-core -y
sudo easy_install pip
sudo pip install virtualenv
sudo pip install virtualenvwrapper

cd ~

mkdir ~/.virtualenvs
echo 'export WORKON_HOME=~/.virtualenvs' >> ~/.bashrc
echo 'source /usr/local/bin/virtualenvwrapper.sh' >> ~/.bashrc
echo 'export PIP_VIRTUALENV_BASE=~/.virtualenvs' >> ~/.bashrc
source ~/.bashrc

Instalando herramientas de desarrollo, pip, virtualenv y virtualenvwrapper

Preparando ambiente para nuestro proyecto

mkvirtualenv curso
pip install django

# Para desativar el virtualenv:
deactivate

# Para volver a activarlo:
workon curso

# Para eliminar un virtualenv
rmvirtualenv curso

Verificamos la instalación

python -c "import django; print(django.get_version())"

Creando un proyecto

django-admin.py startproject curso

Debería haberse creado esta estructura:

curso/
    manage.py
    curso/
        __init__.py
        settings.py
        urls.py
        wsgi.py

Estos archivos son:

  • El directorio curso/ de más afuera es un contenedor para tu proyecto. El nombre no afecta a Django; lo podés renombrar libremente.

  • manage.py: Una utilidad de línea de comandos que te permite interactuar con este proyecto Django de varias maneras. más info: django-admin.py and manage.py.
  • El directorio curso/ interno es el paquete Python para tu proyecto. Su nombre es el nombre de paquete Python que necesitarás usar para importar cualquier cosa adentro del mismo (e.g. import curso.settings).

Estos archivos son:

  • curso/__init__.py: Un archivo vacío que le dice a Python que este directorio debe considerarse un paquete Python.
  • curso/settings.py: Settings/configuración de este proyecto Django. Django settingsdescribe cómo funcionan estos settings.
  • curso/urls.py: Declaración de las URL de este proyecto Django; una “tabla de contenidos” de tu sitio Django. Más info en en URL dispatcher.
  • curso/wsgi.py: Punto de entrada para servir tu proyecto mediante servidores web compatibles con WSGI. Podés ver How to deploy with WSGI para más detalles.

Configuración de Base de Datos

La base de datos por defecto es SQLite

Si se desea utilizar otra base de datos, instalar sus módulos y cambiar lo siguiente:

  • ENGINE – Puede ser 'django.db.backends.sqlite3', 'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql', o 'django.db.backends.oracle'. Hay disponibles otros.
  • NAME – El nombre de tu base de datos.
  • USER, PASSWORD, HOST  – Agregarlos
  • Con SQLite, django creará la base de datos, sino hay que crearla manualmente
python manage.py migrate  # Desde la carpeta curso de más afuera

El servidor de desarrollo

python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
October 03, 2014 - 10:27:07
Django version 1.7, using settings 'curso.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Para que escuche desde todas las ips desde el puerto 8000:

python manage.py runserver 0.0.0.0:8000

Creando una aplicación

  • Proyecto: Es nuestro entorno, por ejemplo nuestro sitio web. Es una colección de configuración y apps para un sitio web particular.
  • Aplicación: Una unidad lógica que hace algo. Ej., un sistema de blog, una base de datos de registros públicos o una aplicación simple de encuestas
  • Un proyecto puede contener múltiples app. Una app puede estar en múltiples proyectos.
python manage.py startapp encuestas
encuestas/
    __init__.py
    models.py
    tests.py
    views.py

Creando modelos

  • Un modelo es la única y definitiva fuente de datos de nuestra información.
  • Contiene los campos y comportamientos esenciales de los datos que vamos a guardar.
  • Django sigue el principio DRY.
  • El objetivo es definir el modelo de datos en un lugar y automáticamente derivar lo demás a partir de éste.

Creando modelos

  • Vamos a crear dos modelos: Pregunta y Eleccion.

  • Una Pregunta tiene un texto de pregunta y una fecha de publicación.

  • Una Eleccion tiene dos campos: el texto de la opción y un contador de votos.

  • Cada Eleccion está asociada a una Encuesta.

Creando modelos

Estos conceptos se representan mediante clases Python. Editamos el archivo encuestas/models.py para que se vea así:

# -*- coding: utf-8 -*-

from django.db import models

class Pregunta(models.Model):
    texto_pregunta = models.CharField(max_length=200)
    pub_date = models.DateTimeField('fecha publicada')


class Eleccion(models.Model):
    pregunta = models.ForeignKey(Pregunta)
    texto_opcion = models.CharField(max_length=200)
    votos = models.IntegerField(default=0)

Más acerca de campos en Model Field Reference

Activando modelos

  • Crear el esquema de base de datos (las sentencias CREATE TABLE) para la app.
  • Crear una API Python de acceso a la base de datos para los objetos Pregunta y Eleccion.

Ese poquito código le da a Django un montón de información. A partir de él, Django puede:

Activando modelos

Primero debemos informarle a nuestro proyecto que la app encuestas está instalada.

Las apps Django son “pluggables”: podés usar una app en múltiples proyectos, y distribuirlas, porque no necesitan estar atadas a una instancia de Django particular.

Activando modelos

Editamos de nuevo el archivo settings.py, y cambiamos el setting INSTALLED_APPS para incluir 'encuestas'. Se verá algo así:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'encuestas',
)

Ahora Django sabe sobre nuestra app polls.

Activando modelos

Corramos otro comando:

python manage.py makemigrations encuestas

Con esto le estás diciendo a django que has hecho modificaciones a tus models

Migrations es con lo que Django guarda los cambios a tus modelos. Son sólo archivos.

Se pueden leer las migraciones del nuevo modelo: encuestas/migrations/0001_initial.py. 

python manage.py sqlmigrate encuestas 0001

Para ver el sql que se va a ejecutar:

Activando modelos

Hacemos efectiva nuestra migración

python manage.py migrate
Operations to perform:
  Apply all migrations: admin, contenttypes, encuestas, auth, sessions
Running migrations:
  Applying encuestas.0001_initial... OK

Obtendriamos algo como esto:

Activando modelos

  • El comando migrate toma todas las migraciones que no se han aplicado aún (les hace un seguimiento con una tabla especial) y las ejecuta en la base de datos, sincronizando los cambios.
  • Migrations es un herramienta muy poderosa y te deja cambiar tus modelos en el tiempo, a medida que desarrollas tu proyecto, sin necesitar borrar tablas y hacer nuevas.
  • Se especializa en actualizar tu base de datos en vivo, sin perder datos.

Activando modelos

En resumen

Jugando con la API

Para invocar el shell de Python, usamos este comando:

python manage.py shell

Usamos esto en lugar de simplemente tipear “python” porque manage.py setea la variable de entorno DJANGO_SETTINGS_MODULE, que le da a Django el import path al archivo settings.py.

Jugando con la API

Exploramos la API de base de datos:

# Importamos las clases de los modelos que escribimos.

>>> from encuestas.models import Pregunta, Eleccion 

# No hay preguntas en el sistema todavía.
>>> Pregunta.objects.all()
[]

# Creamos una nueva Pregunta.
# El soporte para zonas horarias está habilitado por defecto en settings.py
# Django espera entonces un datetime con tzinfo para pub_date.
# Usamos timezone.now() en lugar de datetime.datetime.now()
>>> from django.utils import timezone
>>> q = Pregunta(texto_pregunta="Que hay de nuevo, viejo?", pub_date=timezone.now())

# Guardamos el objeto en la base de datos. Debemos llamar 
# a save() explícitamente.
>>> q.save()

# Ahora tiene un ID. Notar que esto puede decir "1L" en lugar de "1",
# dependiendo de la base de datos que se esté usando. Esto sólo significa
# que el backend del motor de base de datos prefiere devolver los enteros
# como long integer de Python.
>>> q.id
1

Jugando con la API

# Podemos acceder a las columnas de la base de datos como atributos de Python.
>>> q.texto_pregunta
"Que hay de nuevo, viejo?"
>>> q.pub_date
datetime.datetime(2014, 10, 3, 13, 0, 0, 775217, tzinfo=<UTC>)

# Podemos cambiar valores cambiando el valor de los atributos, luego 
# llamamos a save().
>>> q.texto_pregunta = "Que te pasa?"
>>> q.save()

# objects.all() muestra todas las preguntas en la base de datos.
>>> Pregunta.objects.all()
[<Pregunta: Pregunta object>]

Un minuto. <Pregunta: Pregunta object> es, definitivamente, una representación poco útil de este objeto. Arreglemos esto editando los modelos (en el archivo encuestas/models.py) y agregando el método __unicode__() a Pregunta y Eleccion:

Jugando con la API

from django.db import models

class Pregunta(models.Model):
    # ...
    def __unicode__(self):              # __str__ en Python 3
        return self.texto_pregunta

class Eleccion(models.Model):
    # ...
    def __unicode__(self):              # __str__ en Python 3
        return self.texto_opcion

Usamos __unicode__ en vez de __str__ porque estamos trabajando en python 2, python 3 resuelve las discrepancias entre unicode y str haciendo que todo sea en unicode

Jugando con la API

Notar que estos son métodos de python normales, podemos agregar los que queramos

import datetime

from django.db import models
from django.utils import timezone


class Pregunta(models.Model):
    # ...
    def fue_publicada_recientemente(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Más info de manejos de zonas horarias en  la documentación de time zone.

Jugando con la API

Ejecutamos nuestro shell nuevamente

>>> from encuestas.models import Pregunta, Eleccion

# Confirmemos que __unicode__() funciona.
>>> Pregunta.objects.all()
[<Pregunta: Que te pasa?>]

# Django provee una API de búsqueda muy completa a partir de keywords arguments.
>>> Pregunta.objects.filter(id=1)
[<Pregunta: Que te pasa?>]
>>> Pregunta.objects.filter(texto_pregunta__startswith='Que')
[<Pregunta: Que te pasa?>]

# Obtengamos la Pregunta que se publicó este año.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Pregunta.objects.get(pub_date__year=current_year)
<Pregunta: Que te pasa?>

# Si pedimos por un ID que no existe, se levantará una excepción.
>>> Pregunta.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Pregunta matching query does not exist.

Jugando con la API

# Buscar por clave primaria es un caso muy común, Django provee un atajo
# para búsquedas exactas por primary-key.
# Lo siguiente es equivalente a Pregunta.objects.get(id=1).
>>> Pregunta.objects.get(pk=1)
<Pregunta: Que te pasa?>

# Confirmemos que el método que agregamos funciona.
>>> q = Pregunta.objects.get(pk=1)
>>> q.fue_publicada_recientemente()
True

# Démosle a la Pregunta un par de Elecciones. La llamada a create crea un nuevo
# objeto Eleccion, ejecuta la sentencia INSERT, agrega la opción al conjunto
# de opciones disponibles y devuelve el nuevo objeto Eleccion. Django crea
# un conjunto para mantener el "otro lado" de la relación dada por ForeignKey
# (e.g., las opciones de la Pregunta) que se puede acceder vía la API.
>>> q = Pregunta.objects.get(pk=1)

# Muestra las opciones relacionadas -- ninguna por ahora.
>>> q.eleccion_set.all()
[]

Jugando con la API


# Creamos tres opciones.
>>> q.eleccion_set.create(texto_opcion='No mucho', votos=0)
<Eleccion: No mucho>
>>> q.eleccion_set.create(texto_opcion='El cielo', votos=0)
<Eleccion: El cielo>
>>> c = q.eleccion_set.create(texto_opcion=u'Sólo acá, hackeando', votos=0)

# Los objetos Eleccion tienen acceso vía la API a la Pregunta relacionada.
>>> c.pregunta
<Pregunta: Que te pasa?>

# Y vice versa: los objetos Pregunta objects tienen acceso a los 
# objetos Eleccion.
>>> q.eleccion_set.all()
[<Eleccion: No mucho>, <Eleccion: El cielo>, <Eleccion: Sólo acá, hackeando>]
>>> q.eleccion_set.count()
3

Jugando con la API

# La API sigue las relaciones automáticamente tanto como se necesite.
# Se usa doble guión bajo para separar relaciones.
# Esto funciona tantos niveles de profundidad como se quiera; no hay límite.
# Encontremos todas las Elecciones para cualquier Pregunta cuya pub_date es
# este año (reusando la variable 'current_year' que creamos arriba).
>>> Eleccion.objects.filter(pregunta__pub_date__year=current_year)
[<Eleccion: No mucho>, <Eleccion: El cielo>, <Eleccion: Sólo acá, hackeando>]

# Borremos una de las opciones. Para esto usamos delete().
>>> c = q.eleccion_set.filter(texto_opcion__startswith='Sólo acá, hackeando')
>>> c.delete()

Para más información sobre relaciones en modelos, ver Acceder objetos relacionados. Para más detalles sobre cómo usar los doble guión bajo para efectuar búsquedas usando la API, ver Field lookups. Para el detalle completo de la API de base de datos, ver Database API reference.

Enlaces útiles

Resumen

Instalación Base

Esta instalación se realiza 1 vez por equipo. Varía sistema a sistema. Esta es para Ubuntu. Reemplazar todos los .bashrc por .bash_profile para OS X

sudo apt-get update
sudo apt-get install python-setuptools python-dev build-essential git-core -y
sudo easy_install pip
sudo pip install virtualenv
sudo pip install virtualenvwrapper

cd ~

mkdir ~/.virtualenvs
echo 'export WORKON_HOME=~/.virtualenvs' >> ~/.bashrc
echo 'source /usr/local/bin/virtualenvwrapper.sh' >> ~/.bashrc
echo 'export PIP_VIRTUALENV_BASE=~/.virtualenvs' >> ~/.bashrc
source ~/.bashrc

Resumen

Instalación por proyecto

Esta instalación se realiza 1 vez por proyecto, si bien cada desarrollador puede tener su propio esquema de trabajo, este es uno de los más usados

mkvirtualenv curso
pip install django
django-admin.py startproject nombreproyecto

Resumen

Inicializando proyecto

Editar el settings.py a nuestro gusto, y luego generar la base de datos:

python manage.py migrate  # Desde la carpeta donde está el manage.py

Resumen

Inicializando Aplicación

Cada proyecto puede tener 1 o más aplicaciones

python manage.py startapp nombreaplicacion

Resumen

Creando modelos

Desde el archivo models.py replicamos nuestro MER, con nombres de clase para nuestras entidades, y los atributos para nuestros campos

Resumen

Creando Modelos

Ejemplo de MER

Resumen

Creando modelos

En el models.py, transcribir tu MER a código Django, ver referencia de campos. Para el ejemplo anterior:

# -*- coding: utf-8 -*-
from django.db import models

class Etiqueta(models.Model):
    nombre = models.CharField(max_length=200)

class Post(models.Model):
    titulo = models.CharField(max_length=200)
    texto = models.TextField()
    pub_date = models.DateTimeField('fecha publicado')
    etiquetas = models.ManyToManyField(Etiqueta)

class Comentario(models.Model):
    email = models.EmailField()
    comentario = models.TextField()
    post = models.ForeignKey(Post)

Resumen

Creando modelos

Agregamos nuestra nueva app a la variable INSTALLED_APPS de nuestro settings.py

Creamos nuestra migración cada vez que creamos nuevos modelos o modificamos los existentes

python manage.py makemigrations nombreaplicacion

Migramos cada vez que alguien de nuestro equipo ha hecho un makemigrations y hemos bajado esos cambios.

python manage.py migrate
Made with Slides.com