Páginas

viernes, 31 de diciembre de 2010

Web2py ejemplo de paginación

Vamos a paginar una tabla en la vista cada 10 elementos.

en el modelo...................

#recuerde llenar la tabla

db.define_table('persona',
     Field('fecha','datetime'),
     Field('nombre'),
     Field('apellido'),
     Field('profesion'))

en la controladora.............................

def index():
   if len(request.args):
       page=int(request.args[0])
   else:
       page=0

   items_per_page=10   # cantidad de elementos por los cuales hacer la paginación

   limitby=(page*items_per_page,(page+1)*items_per_page+1)    
     
   lista = db(db.persona.id > 0).select(orderby = ~db.persona.fecha,limitby=limitby)
   return dict(lista=lista,page=page,items_per_page=items_per_page)

en la vista...............................................................

index.html

{{extend 'layout.html'}}
<table>
<tr>

<td>Fecha </td>
<td>Nombre</td>
<td>Apellido</td>
<td>Profesion</td>

</tr>
<tr>
{{for i,row in enumerate(lista):}}
{{if i==items_per_page: break}}
<td> {{=row.fecha}}</td>
<td> {{=row.nombre}}</td>  
<td> {{=row.apellido}}</td> 
<td> {{=row.profesion}}</td>

</tr> 
{{pass}}
</table>

<br/>
{{if page:}}
<a href="{{=URL(args=[page-1])}}">anterior</a>
{{pass}}


{{if len(lista)>items_per_page:}}
<a href="{{=URL(args=[page+1])}}">siguiente</a>
{{pass}}

miércoles, 29 de diciembre de 2010

Web2py un ejemplo donde usaremos la función LOAD



Vamos a tratar de comentar los comentarios. Tendremos muchos comentarios padres y cada comentario padre tendrá muchos subcomentarios hijos. Cuando se crea un comentario padre automáticamente se crea un formulario para los subcomentarios, cada hijo sabrá quien es su padre y todo esto ocurrirá en una misma página (algo parecido a lo que hace el facebook).

Este ejemplo funciona satisfactoriamente gracias a la cooperación de Alan Etkin:

en el modelo..........................................

db.define_table('comment',
   Field('body',label='Comentario'))
  
db.define_table('comment2',
   Field('body',label='Comentario'),
   Field('idcomentario',db.comment))  
  
db.comment.body.requires=IS_NOT_EMPTY()
db.comment2.body.requires=IS_NOT_EMPTY()
db.comment2.idcomentario.writable = db.comment2.idcomentario.readable = False



en la controladora........................................

def index():  

    form = SQLFORM(db.comment,fields=['body'])   
    if form.accepts(request.vars,session):
        response.flash='su comentario ha sido posteado'
        
        
    lista = db(db.comment.id>0).select(orderby = ~db.comment.id)
    
    return dict(form=form,lista=lista)
               

def post():   
    id1=request.args[0]
    comentario=db(db.comment.id==request.args[0]).select()[0]
    form = SQLFORM(db.comment2,fields=['body'])
    form.vars.idcomentario=comentario.id
 
    if form.accepts(request.vars,session):
         response.flash='su comentario ha sido posteado'
    elif request.post_vars.has_key('body'):     # Alan Etkin aporte
          if len(request.post_vars['body']) >0:
             response.flash='su comentario ha sido posteado'
             db.comment2.insert(body = request.post_vars['body'],idcomentario = id1)
            
   
    
    comments=db(db.comment2.idcomentario==comentario.id).select()

    return dict(form=form,comments=comments)


en la vista.....................................................

default/index.html

{{extend 'layout.html'}}

<h2>Postea un comentario:</h2>
<div>
{{=form}}
</div>
{{if len(lista):}}
{{for elem in lista:}}
     <h3>{{=elem.body}}</h3>
    <div>{{=LOAD('default','post.load',args=[elem.id],ajax=True)}}</div>
 {{pass}}
{{else:}}
    <h2>No hay comentarios</h2>
{{pass}}



default/post.load  // fijaos que la terminacion es (.load) no (.html) y tampoco se le pone {{extend 'layout.html'}}


{{if len(comments):}}
{{for comment in comments:}}
   <h5>{{=comment.body}}</h5>
{{pass}}
{{else:}}
{{pass}}

{{=form}}

Web2py un ejemplo interesante hecho por mdipierro

Hay veces en las cuales usted tiene dos tablas (ejemplo "cliente", 'dirección') que están unidos entre sí por una referencia y desea crear un único formulario que permite introducir información acerca de un cliente y su dirección por defecto. Asi es como se hace.

Referencia: http://www.web2pyslices.com/main/slices/take_slice/102

en el modelo

db.define_table('client',
     Field('name'))
db.define_table('address',
    Field('client',db.client,writable=False,readable=False),
    Field('street'),Field('city'))

en la controladora

def register():
    form=SQLFORM.factory(db.client,db.address)
    if form.accepts(request.vars):
        id = db.client.insert(**db.client._filter_fields(form.vars))
        form.vars.client=id
        id = db.address.insert(**db.address._filter_fields(form.vars))
        response.flash='Thanks for filling the form'
    return dict(form=form)

Personalizando el menú de la app Welcome en Web2Py - Parte 1

Una de las cosas más interesantes de web2py es su gran versatilidad y sencillez, esto reduce sensiblemente la curva de aprendizaje en comparación con otros frameworks.
En este post -dividido en dos partes- aprenderemos a personalizar el menú por defecto que viene en la app "Welcome" de Web2Py.
En esta primera parte veremos como programar diferentes opciones del menú, en la segunda veremos como modificar la apariencia del menu en la vista.
El fichero en cuestión que modificarás será el siguiente: tu-app/models/menu.py, el cual luce de la siguiente manera:
# -*- coding: utf-8 -*-

#########################################################################
## Customize your APP title, subtitle and menus here
#########################################################################

response.title = request.application
response.subtitle = T('customize me!')
response.meta.author = 'you'
response.meta.description = 'describe your app'
response.meta.keywords = 'bla bla bla'

##########################################
## this is the main application menu
## add/remove items as required
##########################################

response.menu = [
(T('Index'), False, URL(request.application,'default','index'), [])
]

##########################################
## this is here to provide shortcuts
## during development. remove in production
##
## mind that plugins may also affect menu
##########################################

response.menu+=[
(T('Edit'), False, URL('admin', 'default', 'design/%s' % request.application),
[
(T('Controller'), False,
URL('admin', 'default', 'edit/%s/controllers/%s.py' \
% (request.application,request.controller=='appadmin' and
'default' or request.controller))),
(T('View'), False,
URL('admin', 'default', 'edit/%s/views/%s' \
% (request.application,response.view))),
(T('Layout'), False,
URL('admin', 'default', 'edit/%s/views/layout.html' \
% request.application)),
(T('Stylesheet'), False,
URL('admin', 'default', 'edit/%s/static/base.css' \
% request.application)),
(T('DB Model'), False,
URL('admin', 'default', 'edit/%s/models/db.py' \
% request.application)),
(T('Menu Model'), False,
URL('admin', 'default', 'edit/%s/models/menu.py' \
% request.application)),
(T('Database'), False,
URL(request.application, 'appadmin', 'index')),
]
),
]

La línea que nos interesa es la siguiente:

response.menu = [
(T('Index'), False, URL(request.application,'default','index'), [])
]
Aqui tenemos el primer item del menú que viene por defecto y vamos a pasar a describir su contenido. "Index" es lo que aparece visiblemente en el menú. El parámetro "False" es un misterio, aunque seguramente mediante la práctica se puede aprender su utilidad (porque no encontré documentación al respecto). Luego el siguinte parámetro "URL" muy fácil de entender: pasamos la aplicación en cuestion (si dejamos vacios se usa la app presente), el controlador (si dejamos vacio usará "default.py")y la función en cuestión, en este caso index.
Como el primer item de nuestro menú es index, no existen submenús, pero qué si queremos tener un submenú aquí? Muy fácil, creamos una nueva tupla dentro de los corchetes que quedaron vacios, como un parámetro más y podríamos continuar así recursivamente.

Sin embargo tenemos más código, que significa? Significa que cada vez que agregamos un item al menú debemos agregalo de la siguiente manera:

response.menu+=[...] #Entre corchetes va el siguiente menú.

En este caso, el nuevo item es "Edit":

response.menu+=[
(T('Edit'), False, URL('admin', 'default', 'design/%s' % request.application),...

en "URL" debemos seguir los pasos descriptos anteriormente y borrar lo que aparece aqui.
Lo mismo debemos hacer con los siguientes subitems que vienen dentro de la linea. Con simple copie y pegue y sustituyendo nombres y controladores podemos armar sin mas complicaciones nuestros menúes. Es más, con un poco de práctica y experiencia podrías crear varios menúes diferentes. Pero eso es letra para otro post.

Practiquen y prueben. Hagan sus preguntas en los comentarios si algo no quedó claro (seguramente :P ...)y trataremos de responder lo antes posible.

martes, 28 de diciembre de 2010

Web2py un ejemplo donde usaremos la función ajax

Vamos a tratar de modelar lo que hace el gmail a la hora de eliminar los correos en la vista estándar (sin refrescar la pagina), esto se logra usando ajax. La función ajax(url,[name],target)  utilizada en este ejemplo viene por defecto con el Web2py y está basada en jQuery $.ajax.

en el modelo

db.py:

# recuerde llenar la tabla

db.define_table('gmail',   
     Field('correo'))

..................................................................
en la vista

index.html:

{{extend 'layout.html'}}
<INPUT type="button" value="suprimir" onclick="ajax('{{=URL('data')}}',['hijos'],'target');"/><br/><br/>

<span id='target'>
{{if len(lista):}}
{{for row in lista:}}
     {{=INPUT(_type='checkbox', _name='hijos', _value=row.id)}}
    <span style='margin-left:0%'>{{=row.correo}}</span><br/>
     {{pass}}
{{else:}}
    No hay datos
{{pass}}
</span>

.....................................................................................
en la controladora

default.py

def index():
   
    lista = db(db.gmail).select()
   
    return dict(lista=lista)
   
def data():   
    listado = []      
    if request.vars.hijos:
       listacheck = request.vars.hijos
       if not isinstance(listacheck,list):
           listacheck=[listacheck,]         
                 
       for elem in listacheck:                    
             db(db.gmail.id== elem).delete()
            
       if(db(db.gmail.id > 0).count()==0):
           return 'No hay datos'
       else:
          pass   
    
       for row in db(db.gmail).select():
          listado.append(INPUT(_type='checkbox',_name='hijos',_value=row.id))
          listado.append(SPAN(row.correo,_style='margin-left:0.5%'))         
          listado.append(BR())
         
       a = DIV(listado)

    return a

...............................................................................