Vous êtes sur la page 1sur 37

PyDay Rafaela 2010

Mariano Reingart
reingart@gmail.com
Historia del desarrollo Web

HTML estáticas
CGI: código para generar páginas web dinámicas:
Perl
Python (import cgi !)
Código embebido en páginas web:
PHP, JSP, ASP
PSP (python server pages)
Frameworks web: tercera generación
RoR, Struts, Symphony
Django, TurboGears, Web2Py
Modularidad, Reutilización, 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 configuración
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()
Ejemplo PHP
<?php
include 'encabezado.php'; // Título, diseño página
// Conectarse y seleccionar bd
$link = mysql_connect('equipo', 'usuario', 'clave')
or die('Error al conectar: ' . mysql_error());
mysql_select_db('mi_base') or die('Error!');
$query = 'SELECT * FROM my_table'; // Consultar...
$result = mysql_query($query) or die(...);
?><table><?php // Imprimir resultados en HTML
while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
?><tr><?php
foreach ($line as $col_value) {
echo "\t\t<td>$col_value</td>\n"; }
?></tr><?php }
?></table><?php
mysql_free_result($result); // Liberar resultset
mysql_close($link); // cerrar conexión
include 'pie.php'; // Cierre de la página
?>
Web2Py
Framework para desarrollo web
Inicialmente herramienta de enseñanza
Interfaz Administración completa
MVC: modelo-vista-controlador
Bibliotecas avanzadas: XML-RPC, RSS, etc.
Sistema de tickets para errores

Gluon: sesiones, request/response, cookies,


seguridad, plantillas, abstracción bb.dd., caching,
errors, routes, upload/download streaming,
internationalización, etc.
Web2Py: comparación
Influenciado por Ruby on Rails:
Focalizado en el desarrollo rápido
Basado en Python (+ rápido y escalable)
Más fácil administración (por web)
También influenciado por Django:
Generar formularios desde la base de datos
Más compacto, fácil de aprender y configurar
Menos verbose que los frameworks Java
Más claro y simple que frameworks PHP

Desarrollo y Mantenimiento más fácil


Patrón MVC:
Patron de arquitectura de software
Separar Capas:
Datos (Model)
Presentación (View)
Lógica de Control (Controller)
Web2Py: estructura
Model:
Mapeador Objeto-Relacional Propio (DAL)
Fácil configuración, migración (automática)
Controlador
Generar formularios desde la base de datos
Más compacto, fácil de aprender y configurar
Vista
Opera sobre los datos de la vista (o el modelo)
Generación del HTML (formato salida)
Web2Py: Instalación

Bajar y descomprimir
Ejecutar web2py

python web2py.py
o
doble click web2py.exe
Web2Py: Inicio (Startup)

Bajar y ejecutar!
Sin Instalación
Sin Dependencias
Sin Configuración
Funciona en cualquier parte:
Mac, Windows, Unix/Linux
CPython y Jython
Google App Engine
Página de bienvenida

Clickear en "Click here for the administrative interface" para


ingresar a la Interfase administrativa
Interface Administrativa Web
Login (autenticación ingreso)
Administrar, Crear y Diseñar Aplicaciones
Probar/Depurar
Integración con Mercurial
Crear una aplicación
Estructura básica:
admin: interfaz administrativa
examples: ejemplos
welcome: bienvenida

Crear:
imagenes
(ejemplo)
Editar una aplicación
Editar
Código

Presionar en Edit
Modelo:
db.py
Controlador:
default.py
Vista:
index.html
index.html
(htmledit)
Crear una vista, controlador, etc.
En la sección que corresponda (Views, Controller, etc.):
Ir a "create file with filename"
Escribir el nombre del archivo
Presionar submit
Análisis de URL
http://127.0.0.1:8000/app3/default/index.html/a/b/c?name=Max

request.application == "app3"
request.controller == "default"
request.function == "index"
request.extension == "html"
request.args == ["a","b","c"]
request.vars.name == "Max"

Variables de entorno en request.env


Modelo (tablas)
db.define_table("category", SQLField("name"))

db.define_table("image",
SQLField("category_id",db.category), # referencia
SQLField("title", "string"),
SQLField("description", "text"),
SQLField("file","upload"), # algo a subir
SQLField("posted_by",db.auth_user)) # referencia

db.define_table("comment",
SQLField("image_id",db.image), # referencia
SQLField("body","text"),
SQLField("posted_by",db.auth_user), # referencia
SQLField("posted_on","datetime"))
Modelo (más detalles)
# categorias únicas
db.category.name.requires = IS_NOT_IN_DB(db,"category.name")
# category_id será representado por nombre de categoria
db.image.category_id.requires = IS_IN_DB(db,"category.id","%
(name)s")
db.image.title.requires = IS_NOT_EMPTY()
# auto completar campos enviado_por y no mostrarlo en el formulario
db.image.posted_by.default = auth.user.id if auth.user else 0
db.image.posted_by.writable = db.image.posted_by.readable=False
db.comment.posted_by.default = auth.user.id if auth.user else 0
db.comment.posted_by.writable = db.comment.posted_by.readable =
False
# auto completar campo enviado_en y hacerlo de solo lectura
db.comment.posted_on.default = request.now
db.comment.posted_on.writable = False
Modelo (más detalles)
# cambiar etiqueta
db.image.posted_by.label = "Posted by"
# cambiar representación
db.image.posted_by.represent = lambda value: \
"%(first_name)s %(last_name)s" % db.auth_user[value]
# comentarios personalizados
db.image.posted_by.comment = "set automatically"
# cambiar automáticamente cuando se actualiza
db.image.posted_by.update = auth.user.id if auth.user else 0
Controlador (default.py)
def list_images():
return dict(images=db(db.image.id>0).select())
@auth.requires_login()
def post_image():
return dict(form=crud.create(db.image))
@auth.requires_login()
def view_image():
image_id = request.args(0) or redirect(URL(r=request,f="index"))
db.comment.image_id.default = image_id
db.comment.image_id.writable = db.comment.image_id.readable =
False
return dict(form1=crud.read(db.image, image_id),
comments=db(db.comment.image_id==image_id)\
.select(orderby=db.comment.posted_on),
form2=crud.create(db.comment))
Plantillas
default/list_images.html
{{extend "layout.html"}}
<h1>Posted Images</h1>
<ul>
{{for image in images:}}
<li>{{=A(image.title,
_href=URL(r=request,f="view_image",args=image.id))}}</li>
{{pass}}
</ul>
{{=A("post image",_href=URL(r=request,f="post_image"))}}
Ejemplo autenticación
Registrar
(Crear)
usuario en
Authentication
Login
Register

Ingresar
usuario y
contraseña en
Login:
Ejemplo post_image
Ejemplo list_image
Ejemplo view_image
Resumen (hasta ahora)

Procesamiento automático de formularios


Vistas por defecto para todas las funciones
Vista previa imágenes en crud.update/crud.read
Archivos subidos menejados automágicamente
Autenticación incorporada: Registración e Ingreso
Errores - tickets
Errores en el código del usuario tickets al visitante
Los administradores pueden leer tickets online
Se puede acceder a la documentación de web2py
Menús

models/menu.py
menu = [ [‘item’,False,URL(...),[ ] ], ]
False indica si el enlace es el actual
[ ] es un menu opcional
Vistas: {{=MENU(menu)}}
Plantillas

Embeber código: {{... código python aqui ...}}


Insertar el resultado en el HTML: {{=1+3}}
Usar pass para cerrar bloques si no es obvio:
{{for item in "lista":}}...{{=item}}...{{pass}}
{{if True:}}.v.{{else:}}.f.{{pass}}
Funciones: {{def f(a):}}<a href="{{=a}}">{{=a}}
</a>{{return}}
Extender e incluir: {{extend "layout.
html"}} {{include "otherview.html"}}
Helpers: A(...,_href=....)
Más características
Herramientas del administrador (online):

Modelo:
sql log (historial de esquema)
db select (consultas)
db insert (agregar datos)
DAL: abstracción bbdd
Lenguajes: Traducciones a distintos idiomas T()
Archivos Estáticos (sin procesamiento)
Módulos adicionales
¡¡¡EJEMPLOS INCORPORADOS!!!!
Online SQL Designer

http://gaesql.appspot.com/
Layout Builder

http://www.web2py.com/layouts
de django a web2py
shell disponible pero no obligatorio
url.py = ruotes.py (opcional)
sin necesidad de importar web2py
sin archivo de configuración
ambos generan admin
migraciones automáticas
lenguaje de consulta más natural (SQL)
vistas por defecto
llenguaje de vistas: python sin limitaciones
errores se registran (tickets)
Helpers, Cache, soporte completo para GAE, ...
http://www.web2py.com/AlterEgo/default/show/101
Ajax (jQuery)
from gluon.contrib.markdown import WIKI

def ajaxwiki():
form=FORM(TEXTAREA(_id='text'),
INPUT(_type='button',_value='markdown',
_onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
return dict(form=form,html=DIV(_id='html'))

def ajaxwiki_onclick():
return WIKI(request.vars.text).xml()

http://www.web2py.com.ar/examples/simple_examples/ajaxwiki
Recomendaciones

En producción tratar de:

Usar una base de datos de verdad: PostgreSQL ;-)


Deshabilitar migraciones (innecesarias)
Compilar la Aplicación
Encapsular código en módulos (local_import)
Servir usando mod_wsgi y archivos estáticos
@cache y response.render
Fast-downloads (revisar encabezados)
Sesiones a disco (en memoria)
Traducciones: T.set_current_languages('es-AR'...)
Documentación y Ayuda

Web2Py: http://www.web2py.com/
Web2Py en español: http://www.web2py.com.ar/
Documentación Web2Py:
CookBook
Manual (capítulos gratuitos)
Wiki Python:
Plantillas
Módulos últiles (incluye desarrollo web)
Python Argentina: http://www.python.org.ar/