Contenido

De WikiEducator
Saltar a: navegación, buscar



Road Works.svg Trabajo en proceso, espera cambios frecuentes. Tu ayuda y retroalimentación son bienvenidos.
Ver página de charlas.
Road Works.svg


Evolución del desarrollo web

  1. Páginas HTML estáticas
  2. CGI:  código para generar páginas web dinámicas:
  3. Código embebido en páginas web (PHP, JSP, ASP, ...)
  4. Frameworks web:
    • RoR, Struts, Symphony
    • Django, Pylons, Web2Py

Django

Django permite a los desarrolladores crear de forma rápida sitios web de altas prestaciones basados en información almacenada en bases de datos bajo el principio de no repetición (Do Not Repeat Yourself: DRY).

El nombre

Adrian Holovaty, co-creador de Django, es un guitarrista inspirado por Django Reinhardt.

MVC / MVT

MTV: Desarrollo web según un patrón Modelo - Vista - Template (similar al patrón MVC)

  • Modelo: capa de Datos. Describe los datos que gestiona la aplicación. Cada modelo enlaza una tabla en la base de datos.
  • Vista: capa de Negocio. Describe a qué datos hay que acceder y los transforma.
  • Template (plantillas): capa de Presentación. Describe cómo se van a presentar los datos al usuario.


Instalación

https://docs.djangoproject.com/en/1.3/intro/install/

>>> import django
>>> django.VERSION
(1, 3, 0, 'final', 0)

Crear un proyecto

Seguimos el tutorial de django: https://docs.djangoproject.com/en/1.3/intro/tutorial01/

$ django-admin.py startproject sitio_encuestas
$ ls -l
sitio_encuestas/
    __init__.py
    manage.py
    settings.py
    urls.py
__init__.py
Indica que se trata de un paquete.
manage.py
Programa de gestión de django. A partir de ahora será el que usemos para interactuar con el proyecto.
settings.py
Fichero de configuración del proyecto.
urls.py
Gestiona la tabla de urls a las que responde el proyecto.

Servidor de desarrollo

Comprobamos el funcionamiento:

$ cd sitio_encuestas
$ python manage.py runserver
Validating models...
 
0 errors found
Django version 1.3, using settings 'sitio_encuestas.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Comprobamos la dirección con el navegador o

$ curl -I  127.0.0.1:8000
HTTP/1.0 200 OK
Date: Mon, 22 Aug 2011 20:33:33 GMT
Server: WSGIServer/0.1 Python/2.7.1+
Content-Type: text/html

Este servidor ligero nos servirá para desarrollar el proyecto. No está pensado para sitios en producción.

Icon present.gif
Tip: Podemos cambiar el puerto ejecutando:
 $ python manage.py runserver 8080

y También la ip:

 $ python manage.py runserver 0.0.0.0:8000



Configuración del proyecto

Editar settings.py Como el fichero necesita rutas absolutas, podemos añadir esta función:

import os
def ruta_abs(x):
    return os.path.join(os.path.abspath(os.path.dirname(__file__)), x)

Configuración de la base de datos

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

Para usar sqlite:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': ruta_abs('encuestas.db'),                      # Or path to database file if using sqlite3.
    }
}
<source>
Cambiamos también otros datos:
<source lang="python">
TIME_ZONE = 'Europe/Madrid'
LANGUAGE_CODE = 'es-es'

Ejecutamos:

$python manage.py syncdb

que crea las tablas necesarias para el desarrollo de proyecto, incluyendo todas las aplicaciones incuidas en INSTALLED_APPS

Proyectos y aplicaciones

Para optimizar los recursos, un proyecto puede tener varias aplicaciones. Estas aplicaciones se pueden instalar en varios proyectos. Por eso se dice que las aplicaciones de django son "pluglables".

$ python manage.py startapp encuestas

Esto creará el siguiente directorio:

encuestas/
    __init__.py
    models.py
    views.py

Hay que añadir la nueva apliación a INSTALLED_APPS dentro de settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'sitio_encuestas.encuestas'
)

Definición de modelos

models.py

from django.db import models
 
class Encuesta(models.Model):
    pregunta = models.CharField(max_length=200)
    fecha_pub = models.DateTimeField(u'fecha de publicación')
 
    def __unicode__(self):
        return self.pregunta
 
class Opcion(models.Model):
    encuesta = models.ForeignKey(Encuesta)
    opcion = models.CharField(max_length=200)    
    votos = models.IntegerField()
 
    def __unicode__(self):
        return self.opcion
$ python manage.py sql encuestas

Esto hará que veamos el siguiente código SQL:

BEGIN;
CREATE TABLE "encuestas_encuesta" (
    "id" INTEGER NOT NULL PRIMARY KEY,
    "pregunta" VARCHAR(200) NOT NULL,
    "fecha_pub" datetime NOT NULL
)
;
CREATE TABLE "encuestas_opcion" (
    "id" INTEGER NOT NULL PRIMARY KEY,
    "encuesta_id" INTEGER NOT NULL REFERENCES "encuestas_encuesta" ("id"),
    "opcion" VARCHAR(200) NOT NULL,
    "votos" INTEGER NOT NULL
)
;
COMMIT;

Si el código es correcto, ejecutamos:

$ python manage.py syncdb
Creating table encuestas_encuesta
Creating table encuestas_opcion
 
You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use 'lm'): lm
E-mail address: lm@micorreo.com
Password: 
Password (again): 
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
No fixtures found.

Jugando con el ORM de Django

$ python manage.py shell
>>> from encuestas.models import Encuesta, Pregunta # Importa las clases del modelo
 
# No hay encuestas
>>> Encuesta.objects.all()
[]
 
# Creamos una nueva encuesta
>>> import datetime
>>> p = Encuesta(pregunta="¿Cómo va el curso?", fecha_pub=datetime.datetime.now())
 
# Guardamos el objeto en la base de datos
>>> p.save()
 
# Creación de ID automática
>>> p.id
1
 
# Acceso a los valores
>>> p.pregunta
"¿Cómo va el curso?"
>>> p.fecha_pub
datetime.datetime(2011, 7, 15, 12, 00, 53)
 
# Cambio de valores de los atributos
>>> p.pub_date = datetime.datetime(2011, 7, 20, 0, 0)
>>> p.save()
 
# objects.all() muestra todas las encuestas de la base de datos
>>> Encuesta.objects.all()
[<Encuesta: ¿Cómo va el curso?]

Vemos el contenido de la encuesta porque hemos añadido el método __unicode__. Si no, veríamos <Encuesta: Encuesta object> Se crea el método __unicode__ y no __str__ porque los modelos de Django tratan con unicode por defecto.

# API de búsquedas de Django
>>> Encuesta.objects.filter(id=1)
[<Encuesta: ¿Cómo va el curso?>]
>>> Encuesta.objects.filter(pregunta__startswith='¿Cómo')
[<Encuesta: ¿Cómo va el curso?>]
 
# Obtener las encuestas de 2011
>>> Encuesta.objects.get(fecha_pub__year=2011)
<Encuesta: ¿Cómo va el curso?>
 
>>> Encuesta.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Encuesta matching query does not exist.
 
# Búsqueda por clave primaria
>>> Encuesta.objects.get(pk=1)
<Encuesta: ¿Cómo va el curso?>
 
# Vamos a insertar unas opciones para ver cómo funcionan las relaciones.
# Podemos crear las opciones desde la misma encuesta:
 
>>> p = Encuesta.objects.get(pk=1)
 
# Opciones relacionadas con nuestra encuesta:
>>> p.opcion_set.all()
[]
 
# Creamos tres opciones
>>> p.opcion_set.create(opcion='Muy bien', votos=0)
<Opcion: Muy bien>
>>> p.opcion_set.create(opcion='Bien', votos=0)
<Opcion: Bien>
>>> c = p.opcion_set.create(opcion='Regular', votos=0)
 
# Los objetos Opción tienen acceso desde la API a la encuesta a la que pertenecen:
>>> c.encuesta
<Encuesta: ¿Cómo va el curso?>
 
# Y viceversa. Los objetos Encuesta acceden a sus Opciones: 
>>> p.opcion_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.opcion_set.count()
3
 
# La API sigue de forma automática las relaciones.
# Para separar las relaciones se usan dobles guiones bajos.
# Busca todas las Opciones para cualquier encuesta publicada en 2011
>>> Opcion.objects.filter(encuesta__fecha_pub__year=2011)
[<Opcion: Muy bien>, <Opcion: Bien>, <Opcion: Regular>]
 
# Elimina una de las opciones: 
>>> c = p.opcion_set.filter(opcion__startswith='Regular')
>>> c.delete()

Otros métodos en los modelos

Podemos añadir métodos normales a los modelos:

import datetime
class Encuesta(models.Model):
    #...
    def publicada_hoy(self):
        return self.fecha_pub.date() == datetime.date.today()

Y podemos usarlos así:

>>> p = Escuesta.objects.get(pk=1)
>>> p.publicada_hoy()
False

Más información sobre las relaciones entre modelos: Acceder a objetos relacionados. Para más infor sobre cómo usar los dobles guiones bajos para hacer búsquedas por campos mediante la API: búsquedas mediante los campos Para más detalles sobre la API de la base de datos: Referencia de la Base de Datos.


El poderoso Admin de Django

  • El Admin es una herramienta pensada para el "backend", no para el acceso de los usuarios
  • Simplifica la tarea de insertar, modificar y eliminar contenido de la web.

Activar el Admin

  • Por defecto está desactivado.
  • Añade django.contrib.admin a la lista de INSTALLED_APPS en settings.py.
  • Ejecuta
$ python manage.py syncdb
Icon present.gif
Tip: Siempre que añadimos una nueva aplicación hay que actualizar la base de datos


  • Edita el fichero urls.py de tu proyecto y descomenta las líneas que hacen referencia al admin (3 líneas en total)

El fichero tiene que quedar al final algo así:

  1. from django.conf.urls.defaults import *
  2.  
  3. # Uncomment the next two lines to enable the admin:
  4. from django.contrib import admin 	
  5. admin.autodiscover()
  6.  
  7. urlpatterns = patterns('',
  8.     # Example:
  9.     # (r'^mysite/', include('mysite.foo.urls')),
  10.  
  11.     # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
  12.     # to INSTALLED_APPS to enable admin documentation:
  13.     # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
  14.  
  15.     # Uncomment the next line to enable the admin:
  16.     (r'^admin/', include(admin.site.urls)),
  17. )