i'm failing at dynamically changing the dropdown options for one field, after setting another field in a dexterity form.Schema.
the vocabularies are based in a sql database.
specifically i want to update the vocabulary options for township after selecting the county.
right now i am just pulling the full list of townships regardless of the country selected. as all attempts to dynamically change things led to errors.
any help on this would be appreciated. thanks!
from site.py:
from selectionProvider import SelectionProvider
vocabProvider = SelectionProvider()
@grok.provider(IContextSourceBinder)
def countySource(context):
return vocabProvider.getVocabulary('county')
@grok.provider(IContextSourceBinder)
def townshipSource(context):
return vocabProvider.getVocabulary('township')
class IESurrenderSite(form.Schema):
county = schema.Choice(
title=_(u"County"),
source=countySource,
required=True,
)
township = schema.Choice(
title=_(u"Township"),
source=townshipSource,
required=True,
)
...
from selectiorProvider.py:
class SelectionProvider(object):
DB = maap_db.maap_db()
vocabularies = {}
Counties = {}
Townships = {}
def getCountiesDropdownRecordSet(self, object):
"""input:object is a string
"""
print 'in getCountiesDropdownRecordSet'
self.DB.open()
rs = self.DB.RunQuery("Select *, CountyID as [value], name as [title] From County Order By name;")
self.DB.close()
SelectionProvider.CountiesByName = {}
for rec in rs:
SelectionProvider.CountiesByName[rec['CountyID']] = rec['title']
#
return rs
def getTownshipDropdownRecordSet(self, object):
"""input:object is a string
"""
print 'in getTownshipDropdownRecordSet'
self.DB.open()
rs = self.DB.RunQuery("Select *, TownshipID as [value], name as [title] From Township Order By name;")
self.DB.close()
SelectionProvider.TownshipsByName = {}
for rec in rs:
SelectionProvider.TownshipsByName[rec['TownshipID']] = rec['title']
#
return rs
# #
def getDropdownRecordSet(self, object):
"""input:object is a string
"""
print 'in getDropdownRecordSet'
self.DB.open()
rs = self.DB.RunQuery("Select * From DropdownSelections Where object = '%s' Order By seqNo;" % (object))
self.DB.close()
return rs
def buildVocabulary(self, rs, valueField='value', titleField='title'):
"""DO NOT USE directly outside this class, see getVocabulary() or rebuildVocabulary() instead
"""
data = []
for rec in rs:
data.append(SimpleTerm(value=rec[valueField], title=_(rec[titleField])))
#
return SimpleVocabulary(data)
#
def rebuildVocabulary(self, object):
"""Force a fetch from the database and rebuild the vocabulary.
input object: a string, matches the DropdownSelections field
"""
print 'initializing %s' % (object)
if object=="county":
print 'going to CountiesDropdowns'
vocab = self.buildVocabulary(self.getCountiesDropdownRecordSet(object), "CountyID","title")
SelectionProvider.vocabularies[object] = vocab
return vocab
if object=="township":
print 'going to TownshipDropdowns'
vocab = self.buildVocabulary(self.getTownshipDropdownRecordSet(object), "TownshipID","title")
SelectionProvider.vocabularies[object] = vocab
#print _SITE_NAME, '%s selection list initialized.' % (object)
return vocab
else:
vocab = self.buildVocabulary(self.getDropdownRecordSet(object))
SelectionProvider.vocabularies[object] = vocab
return vocab
def getVocabulary(self, object):
"""Retrieve cached vocabulary
input object: a string, matches the DropdownSelections field
"""
recreate = False
if not SelectionProvider.vocabularies.has_key(object):
recreate = True
#
vocab = SelectionProvider.vocabularies.get(object)
if vocab == None or len(vocab) == 0:
recreate = True
#
if recreate:
vocab = self.rebuildVocabulary(object)
#
return vocab
You can do this with plone.formwidget.masterselect Like this (untested, but gives you an idear of how it works):
from zope import schema
from plone.supermodel import model
from plone.formwidget.masterselect import _
from plone.formwidget.masterselect import MasterSelectBoolField
from plone.formwidget.masterselect import MasterSelectField
def getTownshipDynVocab(master):
CountryID = master_value
# search for your township entries by CountryID
# and return it as a DisplayList
return townshipDynamicVocab
class IESurrenderSite(model.Schema):
county = MasterSelectField(
title=_(u"County"),
source=countySource,
slave_fields=(
# Controls the vocab of township
{'name': 'township',
'action': 'vocabulary',
'vocab_method': getTownshipDynVocab,
},
),
required=True,
)
township = schema.Set(
title=_(u"Township"),
value_type=schema.Choice(),
required=False,
)