Curso Python DGA 2011/django/slides

= Introducción a Django =

El framework para los exigentes con los plazos de entrega
Luis Miguel Morillas &lt;lmorillas at xml3k.org&gt; identi.ca: lmorillas

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:
 * 5) * RoR, Struts, Symphony
 * 6) * 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).


 * 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/


 * Comprobamos que está instalado (y la versión)

Creación de un proyecto (cont.)
Un proyecto en Django son 4 ficheros:
 * __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 web de desarrollo
El proyecto incorpora un servidor web:

Servidor web de desarrollo
Comprobamos la dirección con el navegador o

Servidor web de desarrollo (cont.)

 * No está pensado para sitios en producción.
 * Django en producción: https://docs.djangoproject.com/en/1.3/howto/deployment/

Configuración del proyecto

 * Editar settings.py
 * La configuración necesita rutas absolutas --> truco

Configuración de la base de datos
Por defecto, tiene sopote para Postgresql, MySQL, Sqlite y Oracle.

Configuración de la base de datos (cont.)
Para usar sqlite: Para usar otra base de datos: servidor, usuario y base de datos.

Aplicar los cambios
Crea las tablas necesarias para el desarrollo de proyecto, incluyendo todas las aplicaciones incuidas en INSTALLED_APPS

Proyectos y aplicaciones

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

Creación de una aplicación
Esto creará el siguiente directorio:

Incluir la aplicación en el proyecto
Hay que añadir la nueva apliación a INSTALLED_APPS dentro de settings.py

Definición de modelos
models.py

Definición de modelos (cont.)

 * Tipos de datos: https://docs.djangoproject.com/en/1.3/ref/models/fields/
 * Más opciones

Syncdb
Si las tablas tienen datos, ya no modificará la estructura. Soluciones: eliminar los datos de esa aplicación o usar South: http://south.aeracode.org/

Acceso a los datos (cont.)

 * método __unicode__.
 * Si no, veríamos 
 * Se crea el método __unicode__ y no __str__ porque los modelos de Django tratan con unicode por defecto.

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

Acceso a los datos (cont.)
Y podemos usarlos así:

Acceso a los datos (cont.)

 * relaciones entre modelos: https://docs.djangoproject.com/en/1.3/ref/models/relations
 * dobles guiones bajos para hacer búsquedas por campos mediante la API: http://docs.djangoproject.com/en/1.3/topics/db/queries/#field-lookups
 * API de la base de datos: https://docs.djangoproject.com/en/1.3/topics/db/queries/

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
$ python manage.py syncdb
 * Por defecto está desactivado.
 * Añade django.contrib.admin a la lista de INSTALLED_APPS en settings.py.
 * Ejecuta
 * Siempre que añadimos una nueva aplicación hay que actualizar la base de datos

Activar el Admin (cont.)
Archivo: urls.py

Lanzar Admin
$ python manage.py runserver

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:

Hacer el proyecto modificable por el Admin (cont.)

 * 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. admin.site.register(Encuesta, EncuestaAdmin)
 * Preparamos una clase especial para las encuestas (EncuestaAdmin)
 * Indicamos a admin que use esa clase para gestionar nuestro modelo

Fieldsets
Vamos a cambiar el orden en que aparecen los datos:

Añadir objetos relacionados
Tenemos dos opciones: from polls.models import Choice admin.site.register(Choice)
 * Registrar Opcion con el admin como hemos hecho con las Encuestas
 *  box para la clave foránea

Añadir objetos relacionados: inlines

 * Podemos crear las Opciones desde la misma encuesta.

Añadir objetos relacionados: inlines
Con el inline indicamos a Django:
 * que los objetos Opcion se editan en la página de administración de Encuestas
 * 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

 * Por defecto Django muestra el str de cada objeto.
 * más usable mostrar campos individuales.
 * list_display:tupla de nombres de campos (y +)

Listados (cont.)
Podemos especificar el nombre de la columna:

Filtros
Añade a EncuestaAdmin list_filter = ['fecha_pub']

Añade una columna de filtro

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
Es fácil cambiar usando el sistema de plantillas de Django: TEMPLATE_DIRS = (     "/home/my_username/mytemplates", # configura la ruta: rutas absolutas.  )
 * No tiene sentido ver "Django administration" en la parte superior de las páginas.
 * Configura TEMPLATE_DIRS (tupla de rutas donde busca plantillas Django) en el fichero settings.py.

Personalizar la presentación (cont.)

 * 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 de tus templates.
 * Edita la plantilla.

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.

Creación de la interfaz pública
Una vista es un tipo de página web que sirve para una función específica y tiene una plantilla específica. Por ejemplo en un blog podemos tener:
 * La página inicial del Blog (muestra las últimas entradas)
 * El detalle de una entada
 * Página de las entradas por ffechas (día, mes, año)
 * Comentarios

Creación de la interfaz pública (cont.)
En la aplicación de las encuestas:
 * Página índice de Encuestas, que muestre las últimas encuestas
 * Página de detalle de encuestas: Muestra una pregunta con el formulario para votar
 * Página de resultados de una encuesta.

Diseño de URLs
(expresión regular, function python [, diccionario opcional])
 * El primer paso para escribir una vista es diseñar la estructura de la URL.
 * Django asocia una URL con código Python mediante el módulo URLconf.
 * Las urls se controlan con la variable urlpatterns,
 * que es una secuencia de tuplas con el siguiente formato:
 * Django busca por orden y lanza la primera función que cumple el patrón.
 * Cuando Django la encuentra, llama a la función Python con un objeto HttpRequest como primer argumento, valores capturados de la url como argumentos por clave y otros argumentos opcionales (tercer elemento de la tupla)

Diseño de URLs (cont.)

 * URLconf por defecto en urls.py

Diseño de URLs (cont.)
Según nuestro ejemplo si el usuario pide /encuestas/23

Django ejecutará detalle((request=, encuesta_id='23') Los paréntesis de la expresión regular capturan el texto que coincide con el patrón.

El módulo URLconf compila las expresiones regulares para que se ejecuten más rápidas.

Primera vista
python manage.py runserver Navedador: http://localhost:8000/encuestas/ Exception Type: 	ViewDoesNotExist

Primera vista (cont.)
Escribimos las vistas en encuestas/views.py

Vistas que hacen algo
Ahora vamos a escribir vistas que hagan algo realmente Las vistas tienen que devolver:
 * El objeto HttpResponse con el contenido de la página solicitada o
 * Una excepción (por ej. Http404)

Vistas que hacen algo (cont.)
index

Vistas que hacen algo (cont.)

 * Problema: el diseño de la página está integrado en la vista.
 * Si queremos cambiar el aspecto de la página, hay que editar código python.
 * Idea: separar código y presentación usando el sistema de plantillas de Django

Primera plantilla

 * plantilla en una ruta incluida en TEMPLATE_DIRS.
 * '''[directorio_plantillas]/encuestas/index.html"
 * Por seguridad no se extraen las plantillas de la raíz del proyecto.

Atajo: render_to_response

 * ¿Para qué repetir tanto?

Lanzando una respuesta 404 (no encontrado)
Creamos una plantilla para encuestas/detalle.html: Resultado:

Otro atajo: get_object_or_404

 * Si buscamos una secuencia de objetos, podemos usar get_list_or_404

Escribir una vista 404 (página no encontrada)

 * Cuando DEBUG está activado, la vista 404 no se usa y Django muestra el error.
 * Cuando DEBUG está a False, va a buscar un template 404.html en la raíz del directorio de templates.
 * Si no lo encuentra, lanza un Http500. También hay que escribir una plantilla para 500.html.

Detalle.html
Plantilla de detalle.html

Sintaxis del punto
encuesta.opcion_set.all encuesta.opcion_set.all
 * El sistema de plantillas usa la sintaxis del punto para accceder a los atributos.
 * accede a las opciones desde el objeto encuestas
 * equivale a
 * Que devuelve el iterable que recorre el for.
 * Más información en la https://docs.djangoproject.com/en/1.3/topics/templates

Simplificando URLconfs
Podemos usar patrones para evitar repeticiones:

Simplificando URLconfs (cont.)
También se pueden desacoplar:
 * Movemos sitio_encuestas/urls.py a encuestas/urls.py
 * Cambiamos sitio_encuestas/urls.py para eliminar las urls de encuestas e insertamos un include:

Desacoplado
Así quedará encuestas/urls.py Importante: ahora tienen una ruta relativa:
 * podemos instalar la aplicación en distintas URLs
 * ... y la aplicación seguirá funcionando.

Primer formulario

 * actualizar la plantilla del detalle (encuesta/detalle.html)

Primer formulario
Mirando el código:
 * Se usa un radio button para cada opción de la encuesta.
 * El valor de cada opción está asociado al de su id.
 * El nombre de los radio es opcion,
 * así cuando un usuario selecciona una opción
 * y pulsa el botón de votar, envia por POST la información opcion=3 (con el número de id elegido)
 * La acción del formulario es  /encuestas//votar .

Primer formulario (cont.)

 * Los datos se envían por POST.
 * Muy importante porque enviar datos al servidor puede alterar el estado (a diferencia de GET)
 * el forloop.counter indica cuántas veces ha entrado en el bucle.
 * Se usa {% csrf_token %} para evitar Cross Site Request Forgeries.
 * Importante usarlo siempre con POST.

Acción del formulario
(r'^(?P\d+)/votar/$', 'votar')
 * La acción se decide desde URLconf
 * cuando ejecutamos la acción de votar, se llama a la función votar
 * que gestiona los datos enviados y hace algo con ellos:

Acción del formulario (cont.)
La acción puede quedar así:

Acción del formulario (cont.)
Algunas cosas que todavía no hemos visto:
 * request.POST : objeto tipo diccionario
 * permite acceder a los datos enviados por su clave
 * request.POST['opcion'] devuelve el ID de la opción seleccionada como una cadena
 * Los valores de request.POST son siempre cadenas.

Acción del formulario (cont.)

 * Django también proporciona request.GET
 * request.POST['opcion'] lanza una excepción KeyError si no se envía esa información en POST.
 * Después de incrementar el contador de la opción, el código devuelve un HttpResponseRedirect
 * Se usa la función reverse para evitar escribir a mano la URL en la vista.

Vistas genéricas: ¡todavía menos código!!
Django proporciona un atajo llamado sistema de generic views.
 * tareas muy repetitivas en el desarrollo web:
 * obtener datos de la base de datos,
 * según unos parámetros de una URL,
 * cargar una plantilla y
 * devolver la plantilla procesada.

Vistas genéricas: (cont.)
Para convertir nuestra aplicación al uso de vistas genéricas hay que:
 * Convertir el URLconf.
 * Eliminar algunas vistas innecesarias.
 * Corregir la gestión de las URLs por la nuevas vistas

En un proyecto decidiremos antes si es conveniente el uso de vistas genéricas (mejor que refactorizar)

Vistas genéricas: (cont.)
Vamos a usar dos vistas genéricas: ListView y DetailView. Cada vista tiene que conocer: return HttpResponseRedirect(reverse('resultado_encuesta', args=(enc.id,)))
 * el modelo sobre el que actúa (model)
 * DetailView necesita la clave primaria, llamada pk.(hay que cambiar encuesta_id a pk)
 * El nombre resultado_encuesta de la vista resultado sirve para referirse a esta URL después.
 * Por defecto la plantilla de DetailView se llama / _detail.html. en nuestro caso será: encuestas/encuesta_detail.html Se puede usar el argumento template_name
 * La plantilla de ListView se llama por defecto _list.html
 * El contexto lo gestiona de forma autmática generando encuesta_list. La copción context_object_name permite especificar ultimas_encuestas.
 * Podemos eliminar ya las vistas creadas: index, detalle, resultado.
 * Sobre la redicrección:

Inmersión en Python