Search code examples
web2pycascadingdropdownkeyerror

web2py KeyError on using CascadingSelect


I am trying to use the CascadingSelect available here, but get <type 'exceptions.KeyError'>. My models are as below:

# -*- coding: utf-8 -*-
db.define_table('bank_master',
            Field('name'),
            format='%(name)s'
            )

db.define_table('bank_branch',
            Field('bank', db.bank_master),
            Field('name'),
            format='%(name)s'
            )
db.define_table('case_master',
            Field('case_number'),
            Field('bank_branch', db.bank_branch)
            )

if db(db.bank_master.id>0).count() == 0:
    db.bank_master.truncate()
    db.bank_branch.truncate()

    db.bank_master.insert(name='State Bank')
    db.bank_master.insert(name='Central Bank')
    db.bank_master.insert(name='Canara Bank')

    db.bank_branch.insert(name='Austin',bank=1)
    db.bank_branch.insert(name='Dallas',bank=1)
    db.bank_branch.insert(name='Chicago',bank=2)
    db.bank_branch.insert(name='Washington',bank=2)
    db.bank_branch.insert(name='Florida',bank=3)
    db.bank_branch.insert(name='Delhi',bank=3)

cascade = CascadingSelect(db.bank_master,db.bank_branch)
db.case_master.bank_branch.widget = cascade.widget

This is the controller:

def index():
    form = SQLFORM(db.case_master)  
    return dict(form=form)

And this is the view index.html:

{{extend 'layout.html'}}
<h1>Test for Cascade</h1>
<h3>{{=form}}</h3>

This is the error ticket:

Traceback (most recent call last):
File "C:\web2py\gluon\restricted.py", line 219, in restricted
exec(ccode, environment)
File "C:/web2py/applications/cascade_3/controllers/default.py", line 64, in <module>
File "C:\web2py\gluon\globals.py", line 419, in <lambda>
self._caller = lambda f: f()
File "C:/web2py/applications/cascade_3/controllers/default.py", line 9, in index
form = SQLFORM(db.case_master)
File "C:\web2py\gluon\sqlhtml.py", line 1505, in __init__
inp = field.widget(field, default)
File "C:/web2py/applications/cascade_3/models/cascade_widget.py", line 26, in widget
for opt in options]
File "C:\web2py\gluon\packages\dal\pydal\objects.py", line 96, in __getitem__
raise KeyError
KeyError

The CascadingSelect widget works perfectly when the models used by mfreeze is tweaked by adding dummy fields, but somehow when I use my own models as above, the KeyError crops up. Can anyone help in locating my error?


Solution

  • The code for the CascadingSelect widget includes the following:

            opts = [OPTION(format % opt,_value=opt.id,
                                 _parent=opt[str(parent)] if parent else '0') \
                                  for opt in options]
    

    The KeyError is the result of opt[str(parent)] on the second pass through the for loop. In that case, opt is a Row from the db.bank_branch table, and the value of str(parent) is "bank_master" (i.e., the name of the first table). The value of parent is set near the end of the for loop at:

            parent = table
    

    Of course, there is no bank_master field in db.bank_branch (instead, the reference field is simply named "bank"). So, the widget code expects the name of the reference field in the second table to be the same as the name of the first table. In other words, instead of:

        Field('bank', db.bank_master)
    

    it expects:

        Field('bank_master', db.bank_master)
    

    which is a common convention when naming reference fields in web2py.

    So, you can either rename the reference field so it works with the current widget code, or you can modify the code to accommodate alternative reference field names (probably by adding an argument allowing you to specify the name explicitly).