Desarrollo WEB con Web2py 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 ● lenguaje de plantillas: 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/