Diferencia entre revisiones de «Curso Python DGA 2011/django/contenidos»

De WikiEducator
Saltar a: navegación, buscar
Línea 351: Línea 351:
 
El fichero tiene que quedar al final algo así:
 
El fichero tiene que quedar al final algo así:
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" highlight="4, 5, 16">
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" highlight="4, 5, 16">
from django.conf.urls.defaults import *
+
from django.conf.urls.defaults import patterns, include, url
  
 
# Uncomment the next two lines to enable the admin:
 
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
+
from django.contrib import admin
 
admin.autodiscover()
 
admin.autodiscover()
  
 
urlpatterns = patterns('',
 
urlpatterns = patterns('',
     # Example:
+
     # Examples:
     # (r'^mysite/', include('mysite.foo.urls')),
+
     # url(r'^$', 'sitio_encuestas.views.home', name='home'),
 +
    # url(r'^sitio_encuestas/', include('sitio_encuestas.foo.urls')),
  
     # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
+
     # Uncomment the admin/doc line below to enable admin documentation:
    # to INSTALLED_APPS to enable admin documentation:
+
     # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
     # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
  
 
     # Uncomment the next line to enable the admin:
 
     # Uncomment the next line to enable the admin:
     (r'^admin/', include(admin.site.urls)),
+
     url(r'^admin/', include(admin.site.urls)),
 
)
 
)
 
</source>
 
</source>
 +
 +
 +
=== Lanzar Admin ===
 +
$ python manage.py runserver
 +
 +
<source lang="bash">
 +
$ curl http://127.0.0.1:8000/admin/ -I
 +
HTTP/1.0 200 OK
 +
Date: Tue, 23 Aug 2011 15:33:25 GMT
 +
Server: WSGIServer/0.1 Python/2.7.1+
 +
Last-Modified: Tue, 23 Aug 2011 15:33:25 GMT
 +
Expires: Tue, 23 Aug 2011 15:33:25 GMT
 +
Content-Type: text/html; charset=utf-8
 +
Vary: Cookie
 +
Cache-Control: max-age=0
 +
Set-Cookie:  csrftoken=b53bd036b15251d45ed07b15c60e5116; expires=Tue, 21-Aug-2012 15:33:25 GMT; Max-Age=31449600; Path=/
 +
Set-Cookie:  sessionid=2d639f8c86e4e380698c1991fec9d848; expires=Tue, 06-Sep-2011 15:33:25 GMT; Max-Age=1209600; Path=/
 +
</source>
 +
 +
{{Tip| ¿Ves la diferencia entre el comando anterior y el siguiente?}}
 +
 +
<source lang="bash">
 +
HTTP/1.0 301 MOVED PERMANENTLY
 +
Date: Tue, 23 Aug 2011 15:35:12 GMT
 +
Server: WSGIServer/0.1 Python/2.7.1+
 +
Content-Type: text/html; charset=utf-8
 +
Location: http://127.0.0.1:8000/admin/
 +
 +
HTTP/1.0 200 OK
 +
Date: Tue, 23 Aug 2011 15:35:12 GMT
 +
Server: WSGIServer/0.1 Python/2.7.1+
 +
Last-Modified: Tue, 23 Aug 2011 15:35:12 GMT
 +
Expires: Tue, 23 Aug 2011 15:35:12 GMT
 +
Content-Type: text/html; charset=utf-8
 +
Vary: Cookie
 +
Cache-Control: max-age=0
 +
Set-Cookie:  csrftoken=3365df1f4fc610f6d4e9a7ea5f5d97b2; expires=Tue, 21-Aug-2012 15:35:12 GMT; Max-Age=31449600; Path=/
 +
Set-Cookie:  sessionid=1206648ff52d951049b0d830e66a12d9; expires=Tue, 06-Sep-2011 15:35:12 GMT; Max-Age=1209600; Path=/
 +
</source>
 +
 +
Puedes probar la dirección en el navegador: '''http://127.0.0.1:8000/admin/'''
 +
 +
==== Usuarios ====
 +
Tendrás que entrar con el '''superurser''' que creaste la hacer '''syncdb'''.
 +
Si no recuerdas, puedes crear otro superusuario:
 +
$ python manage.py createsuperuser
 +
 +
===Hacer el proyecto modificable por el Admin===
 +
La aplicación Encuestas no aparece. Hay que activarla dentro del admin:
 +
 +
* Crea un fichero '''admin.py''' dentro de la aplicación encuestas con este contenido:
 +
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 +
from encuestas.models import Encuesta
 +
from django.contrib import admin
 +
 +
admin.site.register(Encuesta)
 +
</source>
 +
* Reinicia el servidor de desarrollo. El servidor no detecta la creación de un nuevo archivo.
 +
 +
Se ha creado un completo entorno [http://es.wikipedia.org/wiki/CRUD CRUD] para nuestras encuestas:
 +
* Se genera un formulario automático para el modelo
 +
* Incluye validación de campos
 +
 +
=== Configuración del formulario ===
 +
La configuración se hace mediante el archivo '''admin.py''' creado.
 +
* Preparamos una clase especial para las encuestas ('''EncuestaAdmin''')
 +
* Indicamos a admin que use esa clase para gestionar nuestro modelo
 +
admin.site.register(Encuesta, EncuestaAdmin)
 +
 +
Vamos a cambiar el orden en que aparecen los datos:
 +
 +
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 +
# -*-coding: utf-8 -*-
 +
 +
from encuestas.models import Encuesta
 +
from django.contrib import admin
 +
 +
class EncuestaAdmin(admin.ModelAdmin):
 +
    fieldsets = [
 +
        (None,              {'fields': ['pregunta']}),
 +
        ('Publicación', {'fields': ['fecha_pub']}),
 +
    ]
 +
 +
admin.site.register(Encuesta, EncuestaAdmin)
 +
</source>
 +
 +
Se pueden asignar clases html a cada fielset para personalizar la prsentación. Django ofrece una clase '''collapse''' que muestra el fielset sin expandir por defecto. Útil cuando hay que distribuir muchos contenidos.
 +
 +
class PollAdmin(admin.ModelAdmin):
 +
    fieldsets = [
 +
        (None,              {'fields': ['question']}),
 +
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
 +
    ]
 +
 +
=== Añadir objetos relacionados ===
 +
Nuestro Admin todavía no muestra las opciones para las encuestas.
 +
Tenemos dos opciones:
 +
* Registrar Opcion con el admin como hemos hecho con las Encuestas
 +
from polls.models import Choice
 +
 +
admin.site.register(Choice)
 +
 +
: Admin crea de forma automática un '''<select> box''' para la clave foránea, que incluye todas las encuestas de la base de datos.
 +
* Podemos crear las Opciones desde la misma encuesta.
 +
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 +
from encuestas.models import Encuesta, Opcion
 +
from django.contrib import admin
 +
 +
class OpcionInline(admin.TabularInline):
 +
    model = Opcion
 +
    extra = 3
 +
 +
class EncuestaAdmin(admin.ModelAdmin):
 +
    fieldsets = [
 +
        (None,              {'fields': ['pregunta']}),
 +
        ('Publicación', {'fields': ['fecha_pub'], 'classes': ['collapse']}),
 +
    ]
 +
    inlines = [OpcionInline]
 +
 +
admin.site.register(Encuesta, EncuestaAdmin)
 +
</source>
 +
Con el inline indicamos a Django que los objetos Opcion se editan en la página de administración de Encuestas y que por defecto añade los campos suficientes para añadir 3 Opciones más.
 +
 +
Admin ofrece dos tipos de inlines: StackedInline y TabularInline.
 +
 +
=== Modificar la página de listados ===
 +
La página inicial muestra el listado de todas las Encuestas del sistema. Por defecto Django muestra el str() de cada objeto. Pero es más usable mostrar campos individuales. Useremos la opción '''list_display''', que es una tupla de nombres de campos (también podemos añadir los métodos creados).
 +
 +
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 +
class EncuestaAdmin(admin.ModelAdmin):
 +
    # ...
 +
    list_display = ('pregunta', 'fecha_pub', 'publicada_hoy')
 +
</source>
 +
 +
Podemos especificar el nombre de la columna:
 +
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 +
    def publicada_hoy(self):
 +
        return self.fecha_pub.date() == datetime.date.today()
 +
    publicada_hoy.short_description = '¿Publicada hoy?'
 +
</source>
 +
 +
==== Filtros ====
 +
Añade a EncuestaAdmin
 +
list_filter = ['fecha_pub']
 +
 +
Añade una columna de '''filgro''' que permite filtrar los listados por el campo de fecha de publicación. El filtro se muestra según el tipo del campo de filtrado.
 +
 +
==== Búsqueda ====
 +
search_fields = ['pregunta']
 +
Añade una caja de búsqueda en la parte superior de los listados. Usa '''LIKE''' en las búsquedas.
 +
 +
==== Fechas ====
 +
Como las encuestas tienen un campo con fechas podemos facilitar la navegación cronológica:
 +
date_hierarchy = 'fecha_pub'
 +
 +
==== Paginación ====
 +
  list_per_page = 100
 +
 +
 +
=== Personalizar la presentación ===
 +
No tiene sentido ver '''"Django administration"''' en la parte superior de las páginas.
 +
 +
Es fácil cambiar usando el sistema de plantillas de Django:
 +
 +
* Configura TEMPLATE_DIRS (tupla de rutas donde busca plantillas Django) en el fichero '''settings.py'''.
 +
 +
  TEMPLATE_DIRS = (
 +
      "/home/my_username/mytemplates", # configura la ruta: rutas absolutas.
 +
  )
 +
* Copia la plantilla '''admin/base_site.html''' del directorio de plantillas de Django''(django/contrib/admin/templates)''' a un directorio '''admin''' dentro de una de las rutas que has configurado en el paso anterior. Por ejemplo, si la ruta era '''/home/mi_usuario/sitio_encuestas/plantillas''', habrá que copiar la plantilla como '''/home/my_username/sitio_encuestas/plantillas/admin/base_site.html'''
 +
 +
* Edita la plantilla. La pantilla tiene textos como <nowiki> {% block branding %} y {{ title }} Esas etiquetas {% y {{</nowiki> son parte del elenguaje de plantillas de Django.
 +
 +
Astute readers will ask: But if TEMPLATE_DIRS was empty by default, how was Django finding the default admin templates? The answer is that, by default, Django automatically looks for a templates/ subdirectory within each app package, for use as a fallback. See the template loader documentation for full information.
 +
 +
=== Configurar la página índice===
 +
Por defecto aparecen todas las aplicaciones de INSTALLED_APPS por orden alfabético.
 +
Para eso hay que cambiar la plantilla '''admin/index.html'''. En lugar de usar la variable '''app_list''', puedes forzar las aplicaciones como quieras.

Revisión de 04:58 24 ago 2011



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 patterns, include, url
  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.     # Examples:
  9.     # url(r'^$', 'sitio_encuestas.views.home', name='home'),
  10.     # url(r'^sitio_encuestas/', include('sitio_encuestas.foo.urls')),
  11.  
  12.     # Uncomment the admin/doc line below to enable admin documentation:
  13.     # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
  14.  
  15.     # Uncomment the next line to enable the admin:
  16.     url(r'^admin/', include(admin.site.urls)),
  17. )


Lanzar Admin

$ python manage.py runserver
$ curl http://127.0.0.1:8000/admin/ -I
HTTP/1.0 200 OK
Date: Tue, 23 Aug 2011 15:33:25 GMT
Server: WSGIServer/0.1 Python/2.7.1+
Last-Modified: Tue, 23 Aug 2011 15:33:25 GMT
Expires: Tue, 23 Aug 2011 15:33:25 GMT
Content-Type: text/html; charset=utf-8
Vary: Cookie
Cache-Control: max-age=0
Set-Cookie:  csrftoken=b53bd036b15251d45ed07b15c60e5116; expires=Tue, 21-Aug-2012 15:33:25 GMT; Max-Age=31449600; Path=/
Set-Cookie:  sessionid=2d639f8c86e4e380698c1991fec9d848; expires=Tue, 06-Sep-2011 15:33:25 GMT; Max-Age=1209600; Path=/
Icon present.gif
Tip: ¿Ves la diferencia entre el comando anterior y el siguiente?


HTTP/1.0 301 MOVED PERMANENTLY
Date: Tue, 23 Aug 2011 15:35:12 GMT
Server: WSGIServer/0.1 Python/2.7.1+
Content-Type: text/html; charset=utf-8
Location: http://127.0.0.1:8000/admin/
 
HTTP/1.0 200 OK
Date: Tue, 23 Aug 2011 15:35:12 GMT
Server: WSGIServer/0.1 Python/2.7.1+
Last-Modified: Tue, 23 Aug 2011 15:35:12 GMT
Expires: Tue, 23 Aug 2011 15:35:12 GMT
Content-Type: text/html; charset=utf-8
Vary: Cookie
Cache-Control: max-age=0
Set-Cookie:  csrftoken=3365df1f4fc610f6d4e9a7ea5f5d97b2; expires=Tue, 21-Aug-2012 15:35:12 GMT; Max-Age=31449600; Path=/
Set-Cookie:  sessionid=1206648ff52d951049b0d830e66a12d9; expires=Tue, 06-Sep-2011 15:35:12 GMT; Max-Age=1209600; Path=/

Puedes probar la dirección en el navegador: http://127.0.0.1:8000/admin/

Usuarios

Tendrás que entrar con el superurser que creaste la hacer syncdb. Si no recuerdas, puedes crear otro superusuario:

$ python manage.py createsuperuser

Hacer el proyecto modificable por el Admin

La aplicación Encuestas no aparece. Hay que activarla dentro del admin:

  • Crea un fichero admin.py dentro de la aplicación encuestas con este contenido:
  1. from encuestas.models import Encuesta
  2. from django.contrib import admin
  3.  
  4. admin.site.register(Encuesta)
  • Reinicia el servidor de desarrollo. El servidor no detecta la creación de un nuevo archivo.

Se ha creado un completo entorno CRUD para nuestras encuestas:

  • Se genera un formulario automático para el modelo
  • Incluye validación de campos

Configuración del formulario

La configuración se hace mediante el archivo admin.py creado.

  • Preparamos una clase especial para las encuestas (EncuestaAdmin)
  • Indicamos a admin que use esa clase para gestionar nuestro modelo
admin.site.register(Encuesta, EncuestaAdmin)

Vamos a cambiar el orden en que aparecen los datos:

  1. # -*-coding: utf-8 -*-
  2.  
  3. from encuestas.models import Encuesta
  4. from django.contrib import admin
  5.  
  6. class EncuestaAdmin(admin.ModelAdmin):
  7.     fieldsets = [
  8.         (None,               {'fields': ['pregunta']}),
  9.         ('Publicación', {'fields': ['fecha_pub']}),
  10.     ]
  11.  
  12. admin.site.register(Encuesta, EncuestaAdmin)

Se pueden asignar clases html a cada fielset para personalizar la prsentación. Django ofrece una clase collapse que muestra el fielset sin expandir por defecto. Útil cuando hay que distribuir muchos contenidos.

class PollAdmin(admin.ModelAdmin):

   fieldsets = [
       (None,               {'fields': ['question']}),
       ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
   ]

Añadir objetos relacionados

Nuestro Admin todavía no muestra las opciones para las encuestas. Tenemos dos opciones:

  • Registrar Opcion con el admin como hemos hecho con las Encuestas
from polls.models import Choice

admin.site.register(Choice)
Admin crea de forma automática un <select> box para la clave foránea, que incluye todas las encuestas de la base de datos.
  • Podemos crear las Opciones desde la misma encuesta.
  1. from encuestas.models import Encuesta, Opcion
  2. from django.contrib import admin
  3.  
  4. class OpcionInline(admin.TabularInline):
  5.     model = Opcion
  6.     extra = 3
  7.  
  8. class EncuestaAdmin(admin.ModelAdmin):
  9.     fieldsets = [
  10.         (None,               {'fields': ['pregunta']}),
  11.         ('Publicación', {'fields': ['fecha_pub'], 'classes': ['collapse']}),
  12.     ]
  13.     inlines = [OpcionInline]
  14.  
  15. admin.site.register(Encuesta, EncuestaAdmin)

Con el inline indicamos a Django que los objetos Opcion se editan en la página de administración de Encuestas y que por defecto añade los campos suficientes para añadir 3 Opciones más.

Admin ofrece dos tipos de inlines: StackedInline y TabularInline.

Modificar la página de listados

La página inicial muestra el listado de todas las Encuestas del sistema. Por defecto Django muestra el str() de cada objeto. Pero es más usable mostrar campos individuales. Useremos la opción list_display, que es una tupla de nombres de campos (también podemos añadir los métodos creados).

  1. class EncuestaAdmin(admin.ModelAdmin):
  2.     # ...
  3.     list_display = ('pregunta', 'fecha_pub', 'publicada_hoy')

Podemos especificar el nombre de la columna:

  1.     def publicada_hoy(self):
  2.         return self.fecha_pub.date() == datetime.date.today()
  3.     publicada_hoy.short_description = '¿Publicada hoy?'

Filtros

Añade a EncuestaAdmin

list_filter = ['fecha_pub']

Añade una columna de filgro que permite filtrar los listados por el campo de fecha de publicación. El filtro se muestra según el tipo del campo de filtrado.

Búsqueda

search_fields = ['pregunta']

Añade una caja de búsqueda en la parte superior de los listados. Usa LIKE en las búsquedas.

Fechas

Como las encuestas tienen un campo con fechas podemos facilitar la navegación cronológica:

date_hierarchy = 'fecha_pub'

Paginación

 list_per_page = 100


Personalizar la presentación

No tiene sentido ver "Django administration" en la parte superior de las páginas.

Es fácil cambiar usando el sistema de plantillas de Django:

  • Configura TEMPLATE_DIRS (tupla de rutas donde busca plantillas Django) en el fichero settings.py.
 TEMPLATE_DIRS = (
     "/home/my_username/mytemplates", # configura la ruta: rutas absolutas.
 )
  • Copia la plantilla admin/base_site.html' del directorio de plantillas de Django(django/contrib/admin/templates) a un directorio admin dentro de una de las rutas que has configurado en el paso anterior. Por ejemplo, si la ruta era /home/mi_usuario/sitio_encuestas/plantillas, habrá que copiar la plantilla como /home/my_username/sitio_encuestas/plantillas/admin/base_site.html
  • Edita la plantilla. La pantilla tiene textos como {% block branding %} y {{ title }} Esas etiquetas {% y {{ son parte del elenguaje de plantillas de Django.

Astute readers will ask: But if TEMPLATE_DIRS was empty by default, how was Django finding the default admin templates? The answer is that, by default, Django automatically looks for a templates/ subdirectory within each app package, for use as a fallback. See the template loader documentation for full information.

Configurar la página índice

Por defecto aparecen todas las aplicaciones de INSTALLED_APPS por orden alfabético. Para eso hay que cambiar la plantilla admin/index.html. En lugar de usar la variable app_list, puedes forzar las aplicaciones como quieras.