Páginas

miércoles, 31 de agosto de 2011

Web2py widget selección en cascada


Referencia: http://www.web2pyslices.com/slices/take_slice/86

En este caso haremos el widget no en los modelos sino como un módulo aparte y lo llamaremos usando import.

en la carpeta Módulos.....

from gluon import *  #  partir de la version 1.96.1
import uuid

class CascadingSelect(object):
    """
       Creates dependent selects based on table relationships.
       Pass the tables in order of least to most specific
       Based on http://web2pyslices.com/main/slices/take_slice/85
    """
    def __init__(self, *tables):
        self.tables = tables
        self.prompt = lambda table:str(table)  
    def widget(self,f,v):
        uid = str(uuid.uuid4())[:8]
        d_id = "cascade-" + uid
        wrapper = TABLE(_id=d_id)
        parent = None; parent_format = None;
        fn =  ''
        vr = 'var dd%s = [];var oi%s = [];\n' % (uid,uid)
        prompt = [self.prompt(table) for table in self.tables]
        vr += 'var pr%s = ["' % uid + '","'.join([str(p) for p in prompt]) + '"];\n'
        f_inp = SQLFORM.widgets.string.widget(f,v)
        f_id = f_inp['_id']
        f_inp['_type'] = "hidden"
        for tc, table in enumerate(self.tables):            
            db = table._db    
            format = table._format           
            options = db(table['id']>0).select()
            id = str(table) + '_' + format[2:-2]            
            opts = [OPTION(format % opt,_value=opt.id,
                                 _parent=opt[str(parent)] if parent else '0') \
                                  for opt in options]
            opts.insert(0, OPTION(prompt[tc],_value=0))
            inp = SELECT(opts ,_parent=str(parent) + \
                                  "_" + str(parent_format),
                                  _id=id,_name=id,
                                  _disabled="disabled" if parent else None)
            wrapper.append(TR(inp))
            next = str(tc + 1)
            vr += 'var p%s = jQuery("#%s #%s"); dd%s.push(p%s);\n' % (tc,d_id,id,uid,tc)           
            vr += 'var i%s = jQuery("option",p%s).clone(); oi%s.push(i%s);\n' % (tc,tc,uid,tc)
            fn_in = 'for (i=%s;i<%s;i+=1){dd%s[i].find("option").remove();'\
                    'dd%s[i].append(\'<option value="0">\' + pr%s[i] + \'</option>\');'\
                    'dd%s[i].attr("disabled","disabled");}\n' % \
                           (next,len(self.tables),uid,uid,uid,uid)
            fn_in +='oi%s[%s].each(function(i){'\
                    'if (jQuery(this).attr("parent") == dd%s[%s].val()){'\
                    'dd%s[%s].append(this);}});' % (uid,next,uid,tc,uid,next)           
            fn_in += 'dd%s[%s].removeAttr("disabled");\n' % (uid,next)
            fn_in += 'jQuery("#%s").val("");' % f_id
            if (tc < len(self.tables)-1):
                fn += 'dd%s[%s].change(function(){%s});\n' % (uid,tc,fn_in)
            else:
                fn_in = 'jQuery("#%s").val(jQuery(this).val());' % f_id
                fn += 'dd%s[%s].change(function(){%s});\n' % (uid,tc,fn_in)
                if v:
                    fn += 'dd%s[%s].val(%s);' % (uid,tc,v)                      
            parent = table
            parent_format = format[2:-2]

        wrapper.append(f_inp)
        wrapper.append(SCRIPT(vr,fn))
        return wrapper

//-------------------------------------------------------------

en el modelo

# recuerde llenar las tablas state y city

db.define_table('state',
                Field('name'),format='%(name)s')
               
db.define_table('city',
                Field('name'),
                Field('state',db.state),format='%(name)s')
               
db.define_table('location',
                Field('name'),               
                Field('location',db.city))

//-----------------------------------------------------------

en la controladora

def index():
    from mymodule import CascadingSelect
   
    cascade = CascadingSelect(db.state,db.city)
    db.location.location.widget = cascade.widget
   
    form = SQLFORM(db.location)
    if form.accepts(request.vars,session):
        response.flash= 'localizacion confirmada'
    return dict(form=form)
   
def mostrar():
    lista = []
    listalocation = db(db.location.id>0).select()
    listacity = db(db.city.id>0).select()
    listastate = db(db.state.id>0).select()
   
    for elem in listalocation :
        for elem2 in listacity:
           for elem3 in listastate:
            if(elem.location == elem2.id) and (elem2.state == elem3.id):
                lista.append([elem.name,elem2.name,elem3.name])
   
    return dict(lista=lista)


//---------------------------------------------------

en las vistas

index.html.........

[{{=A('Mostrar',_href=URL(r=request,c='default',f='mostrar'))}}]
{{=form}}

mostrar.html............

<table>
<tr>
{{for elem in lista:}}
    {{for row in elem:}}
    <td> {{=row}}</td>
{{pass}}
</tr>
{{pass}}
</table>