Sunteți pe pagina 1din 60

Programacin en Python

Parte 7: Desarrollo WEB con Django


Mariano Reingart
reingart@gmail.com
Plataforma Web:

Protocolo HTTP:
Requerimiento
Respuesta
Lenguaje HTML, CSS
Cookies, cache, sesiones, URL
Servidor Web (interfaces, sistemas operativos)
Browsers (capacidades, compatibilidad, etc.)
Tcnicas avanzadas:
Javascript: ajax, comet, etc.
Java Applets, Flash, Silverlight
Historia del desarrollo Web

HTML estticas
CGI: cdigo para generar pginas web dinmicas:
Perl
Python (import cgi !)
Cdigo embebido en pginas web:
PHP, JSP, ASP
PSP (python server pages)
Frameworks web: tercera generacin
RoR, Struts, Symphony
Django, TurboGears, Web2Py
Modularidad, Reutilizacin, Extensibilidad, Seguridad
Ejemplo CGI
#!/usr/bin/python
import MySQLdb
print "Content-Type: text/html\n" # codigo repetitivo trivial
print "<html><head><title>Libros</title></head><body>"
print "<h1>Los ultimos 10 libros</h1><ul>" # html embebido
conexion = MySQLdb.connect(user='yo', passwd='dejame_entrar',
db='mi_base') # codigo duplicado en varios scripts, sin configuracin
cursor = conexion.cursor()
cursor.execute("SELECT nombre FROM libros ORDER BY fecha_pub
DESC LIMIT 10")
for fila in cursor.fetchall():
print "<li> %s</li>" % fila[0]
print "</ul></body></html>"
conexion.close()
Patrn MVC:
Patron de arquitectura de software
Separar Capas:
Datos (Model)
Presentacin (View)
Lgica de Control (Controller)
Patrn MVC: Modelo

Usualmente utiliza Base de Datos Relacional


Incorpora Lgica de Datos
Almacenamiento (acciones)
Integridad
Validaciones
Comportamiento
Clases Python: Objetos del Mundo Real
Atributos
Mtodos
Interrelaciones (herencia, colecciones, etc.)
Mapeadores Objeto-Relacional
Patrn MVC: Vista

Usualmente plantillas HTML, PDF, etc.


Incorpora Lgica de Presentacin
Mostrar Modelo
Formularios
Estilos
Herencia y Reuso
Lenguaje de Plantillas
XML compatible: ej. Kid, Genshi
X/HTML: ej. PyPa (comentarios/tags HTML)
Propios: CherryPy, Django
Flexibilidad codificacin vs edicin
Patrn MVC: Controlador

Usualmente mdulos python dentro servidor Web


Incorpora Lgica de Control
Responder eventos
Producir cambios al modelo
Actualizar vista
Despachador/Ruteo segn URL
Archivos / parmetros
Mdulos/Funciones (ej. mod_python)
Expresiones Regulares
Middleware: software intermedio (cache, sesiones,
abstraccin servidor web, etc.)
Django

Framework para desarrollo web


Inicialmente pginas de noticias
Automatizacin (ej. Interfaz Administracin)
D.R.Y.: no repetirse (don't repeat youself)
Gestin avanzada de contenidos
MTV: modelo-plantilla-vista (similar a MVC)
Mapeador Objeto Relacional
Diseo de URL elegantes y flexbles
Sistema de plantillas
Sistema de cache
Internacionalizacin
Django: objetivo

Construir en profundidad, forma dinmica y rpida


Focalizar partes interesantes, aliviar repetitivas
Abstracciones de alto nivel
Atajos para tareas frecuentes
Convenciones para resolver problemas
Extensible para temas fuera del framework
Acoplamiento dbil (propsitos clave)
Mejora Continua (django 0.96, 1.0, 1.1)
Proyectos con aplicaciones "enchufables"
Django: modelo

Mapeador Objeto-Relacional Propio


Posibilidad de incorporar lgica de datos
Independencia de la Base de Datos
Fcil configuracin y despliegue

# models.py (las tablas de la base de datos)


from django.db import models
class Book(models.Model):
name = models.CharField(maxlength=50)
pub_date = models.DateField()
Django: vistas ("controlador")

Opera sobre el modelo


Generacin de la respuesta

# views.py (la parte lgica)


from django.shortcuts import render_to_response
from models import Book

def latest_books(request):
book_list = Book.objects.order_by('-pub_date')[:10]
return render_to_response('latest_books.html',
{'book_list': book_list})
Django: plantillas ("vistas")

Opera sobre los datos de la vista (o el modelo)


Generacin del HTML (formato salida)

# latest_books.html (la plantilla)


<html><head><title>Books</title></head>
<body><h1>Books</h1><ul>
{ % for book in book_list %}
<li>{{ book.name }}</li>
{ % endfor %}
</ul></body></html>
Django: despachador/ruteador

Determina que vista ("controlador") segn URL


# urls.py (la configuracin URL)
from django.conf.urls.defaults import *
import views
urlpatterns = patterns('',
(r'latest/$', views.latest_books),
)
Django:
Procesamiento
de peticiones
Django: Errores 404
Django: Instalacin

Easy_install:

easy_install django

Cdigo fuente
1. Baja el tarball, que se llamar algo as como
Django-0.96.tar.gz
2. tar xzvf Django-*.tar.gz
3. cd Django-*
4. sudo python setup.py install
Django: Comprobacin

Iniciar Python:

>>> import django


>>> django.VERSION
(0, 96, None)

Temas de despliegue:
Hosting compartido, verificar versin
Incluir django con el proyecto

Crea site-packages/django.pth y agrega el


directorio o actualiza tu PYTHONPATH.
Django: Instalar la base de datos

Opciones:
PostgreSQL (recomendado): PsycoPg y Windows
MySQL: MySQLDb
SqLite (para dearrollo, proyectos chicos)
No usar base de datos! (algunas herramientas
extras no estarn disponibles)
Django: Comenzar un proyecto

Estructura misito/:
__init__.py: declara el paquete
manage.py: utilitario para administrar
settings.py: opciones / configuraciones
urls.py: "tabla de contenidos" segn URLs

misitio no debera estar en la carpeta del servidor


web
Django: Servidor de desarrollo

Django incluye un servidor ligero para desarrollo:

python manage.py runserver.

Validating models...
0 errors found
Django version 1.1, using settings 'misitio.settings'
Development server is running at http://127.0.0.1:
8000/
Quit the server with CTRL-BREAK.
Django: Pgina de bienvenida
It worked!
Congratulations on your first Django-powered page.
Of course, you haven't actually done any work yet. Here's what to do next:
If you plan to use a database, edit the DATABASE_* settings in misitio/settings.py.
Start your first app by running python misitio/manage.py startapp [appname].
You're seeing this message because you have DEBUG = True in your Django settings file and you
haven't configured any URLs. Get to work!
Django: Servidor de desarrollo

Django incluye un servidor ligero para desarrollo:

python manage.py runserver.

Validating models...
0 errors found
Django version 1.1, using settings 'misitio.settings'
Development server is running at http://127.0.0.1:
8000/
Quit the server with CTRL-BREAK.
Django: Vista dinmica

Crear un archivo views.py en misitio/:

from django.http import HttpResponse


import datetime
def fecha_actual(request):
now = datetime.datetime.now()
html = "<html><body>Ahora es %s.
</body></html>" % now
return HttpResponse(html)
Django: Mapear url a nuestra vista

Editar el archivo urls.py en misitio/:

from django.conf.urls.defaults import *


from misitio.views import fecha_actual

urlpatterns = patterns('',
(r'^fecha/$', fecha_actual),
)

Probar http://localhost:8000/fecha
Django: URL "dinmicas"

Agregar a urlpatterns en el archivo urls.py en


misitio/:
(r'^fecha/mas/(\d{1,2})/$', fecha_futura),
# (los parntesis indican el parmetro)
Agregar a views.py:
def fecha_futura(request, horas):
horas = int(horas)
dt = datetime.datetime.now() + datetime.timedelta(hours=horas)
html = "<html><body>En %s hora(s), van a ser las %s.
</body></html>" % (horas, dt)
return HttpResponse(html)
Probar http://localhost:8000/fecha/mas/1/
Django: Errores en Desarrollo

Si DEBUG=True nos mostrar una pgina de error:


Informacin de la excepcin (tipo, lugar, entorno,
versin, fecha, etc.)
Traceback (formateado y texyo plano)
Variables locales
Informacin del pedido (GET/POST)
Settings
Django: Plantillas: filosofa y limitaciones

Filosofa:
Separar lgica negocios de lgica presentacin
Sintxis independiente HTML/XML (ej texto)
Editar cdigo HTML directamente (!wyswyg)
Diseadores != Programadores (no python!)
No inventar un lenguaje de programacin

Limitaciones:
No asignar variables ni modificarlas
No llamar a cdigo python crudo
Django: Plantillas: variables

Reemplazar por el valor: {{ variable }}


Bsqueda del punto: {{foo.bar}}
Diccionario (por ej. foo["bar"])
Atributo (por ej. foo.bar)
Llamada de mtodo (por ej. foo.bar())
ndice de lista (por ej. foo[bar])
Variables no encontradas: devuelve "" (default)
Filtros:
{{ cadena|lower }} aplica filtro lower
{{ my_text|escape|linebreaks }} convertir <p>
{{ bio|truncatewords:"30" }} pasar parmetro
Django: Plantillas: etiquetas
Condiciones :
{% if %} se puede usar and y or (no mezclar)
{% ifequal algo otro %} para comparar
Bucles:
{% for x in y %} similar al for de python
forloop.counter (enumeracin)
forloop.first, forloop.last (1 o ult. elemento)
forloop.parentloop (loop anidado)
Varios:
{# comentario #} (solo una lnea)
{ % include 'nav.html' %} incluir otra plantilla
Django: Plantillas: herencia
Plantillas base.html:

{% block nombre %}texto{ % endblock %}


Plantillas hijas pueden reemplazar los bloques

Plantillas hija.html (reemplazamos los bloques):

{% extends "base.html" %}
{% block nombre %}Texto reemplazado{ %
endblock %} redefine el bloque title de base.html
Django: Plantillas por cdigo
C:\...>python manage.py shell
>>> from django.template import Template, Context
>>> raw_template = """<p>Estimado {{ nombre }},</p>
... <p>Gracias por pedir {{ producto }} de {{ compania }}.
... Se envia el {{ envio|date:"F j, Y" }}.</p>
... {% if garantia %} <p>Garantia sera incluida </p>{% endif %}"""
>>> t = Template(raw_template)
>>> import datetime
>>> c = Context({'nombre': 'Juan Perez', 'producto': 'Notebook',
... 'compania': 'CompuVentas', 'envio': datetime.date(2009, 4, 2),
... 'garantia': True})
>>> t.render(c)
u'<p>Estimado Juan Perez,</p>\n <p>Gracias por pedir Notebook de
CompuVentas. Se envia el April 2, 2009.</p>\n <p>La garantia sera
i
ncluida en el pedido.</p>\n</p>'
Django: Plantillas desde archivo

Editar settings.py indicando donde estan plantillas:

import os
curdir = os.path.dirname(__file__)
ruta = os.path.join(curdir, 'templates').replace('\\','/')
TEMPLATE_DIRS = (
ruta, # indicar el path completo de las plantillas
)
Django: Plantillas en vistas

Editar views.py:

from django.shortcuts import render_to_response


import datetime

def fecha_actual(request):
ahora = datetime.datetime.now()
return render_to_response('fecha.html', {'fecha':
ahora})
Django: Plantillas en vistas
Editar templates/base.html:
<html><head>
<title>{% block title %}{% endblock %}</title>
</head><body><h1>Sitio de prueba</h1>
{% block content %}{% endblock %}
{% block footer %}<hr>Gracias{% endblock %}
</body></html>
Editar templates/fecha.html:
{% extends "base.html" %}
{% block title %}Fecha Actual{% endblock %}
{% block content %}<p>Ahora es {{ fecha }}.</p>
{% endblock %}
Django: Aplicaciones

Crear una aplicacin para el modularizar el sitio:

python manage.py startapp libreria

Estructura msitio/libreria:

models.py: modelos
tests.py: pruebas
views.py: vistas
__init__.py: mdulo python
Django: Aplicaciones: configuracin

Modificar settings.py:

# configurar la base de datos


DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = os.path.join(curdir, 'misitio.
db')

# Agregar la aplicacion
INSTALLED_APPS = (
'misitio.libros',
)
Django: Modelo: definicin
Agregar clases a libros/models.py:
class Editorial(models.Model):
nombre = models.CharField(maxlength=30)
website = models.URLField()
class Autor(models.Model):
nombre = models.CharField(maxlength=10)
email = models.EmailField()
foto = models.ImageField(upload_to='/tmp')
class Book(models.Model):
titulo = models.CharField(maxlength=100)
autores = models.ManyToManyField(Autor)
editorial = models.ForeignKey(Editorial)
fecha = models.DateField()
tapa = models.ImageField(upload_to='/tmp',null=True)
Django: Modelo: sincronizar la base
Para crear las tablas ejecutar:
python manage.py syncdb

C:\Documents and Settings\Mariano\misitio>python manage.py


syncdb
Creating table
auth_permission, auth_group, auth_user, auth_message, django_cont
ent_type, django_session, django_site
Creating table libros_editorial, libros_autor, libros_book

Would you like to create superuser now? (yes/no): yes


Username: admin
E-mail address: admin@domain.com
Password:
Password (again):
Django: Modelo: esquema sql
C:\DOCUME~1\Mariano\misitio>python manage.py sql libreria
BEGIN;
CREATE TABLE "libreria_editorial" (
"id" integer NOT NULL PRIMARY KEY,
"nombre" varchar(30) NOT NULL, "website" varchar(200) NOT NULL
);
CREATE TABLE "libreria_autor" (
"id" integer NOT NULL PRIMARY KEY, "nombre" varchar(10) NOT NULL,
"email" varchar(75) NOT NULL, "foto" varchar(100) NOT NULL
);
CREATE TABLE "libreria_libro" (
"id" integer NOT NULL PRIMARY KEY, "titulo" varchar(100) NOT NULL,
"editorial_id" integer NOT NULL REFERENCES "libreria_editorial" ("id"),
"fecha" date NOT NULL, "tapa" varchar(100)
);
CREATE TABLE "libreria_libro_autores" (
"id" integer NOT NULL PRIMARY KEY,
"libro_id" integer NOT NULL REFERENCES "libreria_libro" ("id"),
"autor_id" integer NOT NULL REFERENCES "libreria_autor" ("id"),
UNIQUE ("libro_id", "autor_id")
);
COMMIT;
Django: Modelo: shell de la base de datos
Con Django es posible conectarse a la base de datos:

C:\DOCUME~1\Mariano\misitio>python manage.py dbshell


SQLite version 3.6.17
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> alter table libreria_libro add column tapa varchar(100);
sqlite>

Util para:
Consultar el esquema SQL
Modificar el esquema SQL
Django: Modelo: insertar datos
Ingresar al interprete dentro del sitio:
python manage.py shell

>>> from libreria.models import Editorial, Autor, Libro


>>> e1 = Editorial(nombre='Addison-Wesley', website='http:
//www.apress.com/')
>>> e1.save()
>>> e2 = Editorial(nombre="O'Reilly", website='http://www.
oreilly.com/')
>>> e2.save()
>>> e2.id
2
Django: Modelo: actualizar datos
En el interprete:

>>> a1 = Autor(nombre="Guido Van Rossum", email="


gvr@google.com")
>>> a1.save()

>>> a1.email="guido@google.com" # modifico


>>> a1.save()
Django: Modelo: actualizar datos (2)
En el interprete:

>>> import datetime


>>> e1 = Editorial.objects.get(nombre="O'Reilly')
>>> l1 = Libro(titulo="Tutorial de Python")
>>> l1.editorial=e1
>>> l1.fecha = datetime.date.today()
>>> l1.save()
>>> l1.autores.add(a1) # agrego un autor
>>> l1.save()
Django: Modelo: consultar datos
Dentro del shell:

>>> editoriales = Editorial.objects.all() # todos objetos (mgr)


>>> editoriales
[<Editorial: Addison-Wesley>, <Editorial: O'Reilly>]

>>> Editorial.objects.filter(nombre="O'Reilly") # filtro


[<Editorial: O'Reilly>]

>>> Editorial.objects.filter(website__contains="www")
[<Editorial: Addison-Wesley>, <Editorial: O'Reilly>]

>>> Editorial.objects.get(id=2) # obtengo obj individual


<Editorial: O'Reilly>
Django: Modelo: ordenando/encadenando
Dentro del shell:

>>> Editorial.objects.order_by("-nombre","website")
[<Editorial: O'Reilly>, <Editorial: Apress>, <Editorial:
Addison-Wesley>]

>>> Editorial.objects.filter(website__contains="a").order_by("-
nombre")
[<Editorial: Apress>, <Editorial: Addison-Wesley>]

>>> Editorial.objects.all()[0] # rebanar (LIMIT)


[<Editorial: O'Reilly>]
Django: Modelo: eliminando datos
Dentro del shell:

>>> e = Editorial.objects.get(nombre="Addison-Wesley")
>>> e.delete()
>>> Editorial.objects.all()
[<Editorial: O'Reilly>, <Editorial: Apress>]

>>> editoriales = Editorial.objects.all() # borrar todos


>>> editoriales.delete()
>>> Editorial.objects.all()
Django: Admin
Editar settings.py, agregar a INSTALLED_APPS:
'django.contrib.auth',

Editar urls.py, descomentar:


from django.contrib import admin
admin.autodiscover()
(r'^admin/', include(admin.site.urls)),

Sincronizar la base para la app admin:


python manage.py syncdb

Probar http://localhost:8000/admin
Django: Admin: agregar nuestra app

Crear libreria/admin.py:

from misitio.libreria.models import Editorial, Autor,


Libro
from django.contrib import admin

admin.site.register(Libro)
admin.site.register(Editorial)
admin.site.register(Autor)

Reiniciar el servidor!
Django: Admin: Indice
Ingresar a http://localhost:8000/admin/
Aplicaciones,
Objetos / Acciones
Django: Admin: Editando un objeto
Django: Formularios

Crear libreria/foms.py:

from misitio.libreria.models import Editorial, Autor,


Libro
from django.contrib import admin

admin.site.register(Libro)
admin.site.register(Editorial)
admin.site.register(Autor)

Reiniciar el servidor!
Django: Formularios
Crear libreria/foms.py:
from django import forms
class BusquedaForm(forms.Form):
texto = forms.CharField(max_length=100, required=True)
Crear templates/busqueda.html:
<form action="/libreria/buscar/" method="post">
<label for="id_texto">Texto</label>
{{ form.texto }} {{ form.texto.errors }}<br/>
<input type="submit" value="Buscar" /> </form>
Ventajas:
Validacin (por campo y por formulario)
Conversin tipos de datos
Manejo de errores y widgets html
Django: Formularios (vista)
Agregar la vista libreria/views.py:
from libreria.forms import BusquedaForm
def buscar(request):
if request.method == 'POST': # si enviaron...
form = BusquedaForm(request.POST) # creo el form
if form.is_valid(): # pasaron las validaciones?
texto = form.cleaned_data['texto']
libros = Libro.objects.filter(titulo__contains=texto)
return render_to_response('busqueda.html', {
'texto': texto, 'libros': libros })
else:
form = BusquedaForm() # An unbound form
return render_to_response('buscar.html', {'form': form,})
Django: Formulario (plantilla resultados)
Agregar la plantilla templates/busqueda.py:

<ul>
{% for libro in libros %}
<li><b><a href="{{ libro.tapa.url }}">{{ libro.titulo }}
</a></b>:
{% for autor in libro.autores.all %} {{ autor.nombre }},
{% endfor %}
{{ libro.editorial.nombre }}, <i>{{libro.fecha}}</i>
{% endfor %}
</ul>
Django: Servir contenidos estticos*
Modificar settings.py:

# Ruta absoluta al directorio de media (estatico)


MEDIA_ROOT = os.path.join(curdir, 'static')

# URL que sirve MEDIA_ROOT.


MEDIA_URL = 'http://localhost:8000/static/'

Modificar urls.py:
urlpatterns = patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT}),
)
Django: flatpages: pginas "estticas"

Funcionamiento:
Funcionan ante errores 404 (pgina no encontrada)
Muestran contenido html "esttico"
Creadas por la interfaz admin o por cdigo
Permiten elegir la plantillas, por defecto
tempates/flatpages/default.html:
<html><head><title>{{ flatpage.title }}</title></head>
<body>
{{ flatpage.content }}
</body>
</html>
Django: flatpages: instalacin
Agregar app y middleware en settings.py:
INSTALLED_APPS = (
'django.contrib.flatpages',
)
MIDDLEWARE_CLASSES = (
'django.contrib.flatpages.middleware.
FlatpageFallbackMiddleware',
)
Actualizar la base de datos:
C:>python manage.py syncdb
Creating table django_flatpage
Installing index for flatpages.FlatPage model
Crear plantilla templates/flatpages/default.html
Crear pginas en el admin
Django: flatpages: ejemplo
Documentacin y Ayuda

Django: http://www.djangoproject.com/
Django en espaol: http://django.es/
Libro Django en espaol (traduccin)
Wiki Python:
Plantillas
Mdulos ltiles (incluye desarrollo web)
Python Argentina: http://www.python.org.ar/

S-ar putea să vă placă și