add parameter to get the list field options from an external source (#1459)

This commit is contained in:
Frédéric Péters 2012-05-24 09:13:27 +02:00
parent dc9530c6a5
commit edbd5b3a38
4 changed files with 142 additions and 14 deletions

75
wcs/data_sources.py Normal file
View File

@ -0,0 +1,75 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2012 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
from quixote.html import htmltext, TemplateIO
from qommon.form import *
data_source_functions = {}
def register_data_source_function(function, function_name=None):
if not function_name:
function_name = function.__name__
if not function_name in data_source_functions:
data_source_functions[function_name] = function
class DataSourceSelectionWidget(CompositeWidget):
def __init__(self, name, value = None, **kwargs):
CompositeWidget.__init__(self, name, value, **kwargs)
if not value:
value = {}
options = [('none', _('None')),
('formula', _('Formula (Python)'))]
self.add(SingleSelectWidget, 'type', options = options, value = value.get('type'))
self.parse()
if not self.value:
self.value = {}
if self.value.get('type') == 'formula':
self.add(StringWidget, 'value', value = value.get('value'))
self.add(SubmitWidget, 'apply', value = _('Apply'))
self._parsed = False
def _parse(self, request):
values = {}
for name in ('type', 'value'):
value = self.get(name)
if value:
values[name] = value
if values.get('data', '').startswith('------'):
values = None
self.value = values or None
def render_content(self):
r = TemplateIO(html=True)
for widget in self.get_widgets():
r += widget.render_content()
return r.getvalue()
def get_items(data_source):
if data_source.get('type') == 'formula':
vars = get_publisher().substitutions.get_context_variables()
return eval(data_source.get('value'), vars, data_source_functions)
return []

View File

@ -33,6 +33,8 @@ from qommon import get_cfg, get_logger
from qommon.strftime import strftime
import data_sources
def fixcsv(self, v):
if type(s) is not str: return s
@ -113,6 +115,7 @@ class Field:
convert_value_to_str = None
in_listing = False
prefill = None
store_display_value = None
stats = None
@ -649,33 +652,72 @@ class ItemField(WidgetField):
items = []
show_as_radio = False
widget_class = SingleSelectHintWidget
data_source = None
def __init__(self, **kwargs):
self.items = []
WidgetField.__init__(self, **kwargs)
def perform_more_widget_changes(self, form, kwargs, edit = True):
if edit:
kwargs['options'] = self.items or [(None, '---')]
if self.show_as_radio:
self.widget_class = RadiobuttonsWidget
if len(kwargs['options']) > 3 or len(self.items[0]) > 10:
# TODO: absence/presence of delimitor should be an option
kwargs['delim'] = htmltext('<br />')
if self.data_source:
kwargs['options'] = data_sources.get_items(self.data_source)
elif self.items:
kwargs['options'] = self.items
else:
self.widget_class = StringWidget
kwargs['options'] = [(None, '---')]
if self.show_as_radio:
self.widget_class = RadiobuttonsWidget
if len(kwargs['options']) > 3 or len(self.items[0]) > 10:
# TODO: absence/presence of delimitor should be an option
kwargs['delim'] = htmltext('<br />')
def get_display_value(self, value):
real_value = value
label_value = str(value)
kwargs = {}
self.perform_more_widget_changes(form, kwargs, False)
if type(kwargs['options'][0]) in (tuple, list):
for key, value in kwargs['options']:
if str(key) == str(real_value):
label_value = value
break
return label_value
def add_to_view_form(self, form, value = None):
real_value = value
label_value = self.get_display_value(value)
self.field_key = 'f%s' % self.id
get_request().form[self.field_key + '_label'] = label_value # :/
form.add(StringWidget, self.field_key + '_label', title = self.label,
value=label_value, readonly = 'readonly', size=len(label_value))
form.add(HiddenWidget, self.field_key, value=real_value)
def store_display_value(self, value):
kwargs = {}
self.perform_more_widget_changes(None, kwargs, False)
if type(kwargs['options'][0]) in (tuple, list):
for key, option_value in kwargs['options']:
if str(key) == str(value):
return option_value
return str(value)
def fill_admin_form(self, form):
WidgetField.fill_admin_form(self, form)
form.add(WidgetList, 'items', title = _('Items'), element_type = StringWidget,
value = self.items, required = True,
element_kwargs = {'render_br': False, 'size': 50},
add_element_label = _('Add item'))
form.add(CheckboxWidget, 'show_as_radio', title = _('Show as radio buttons'),
value = self.show_as_radio)
form.add(WidgetList, 'items', title = _('Items'), element_type = StringWidget,
value = self.items, required = False,
element_kwargs = {'render_br': False, 'size': 50},
add_element_label = _('Add item'))
form.add(data_sources.DataSourceSelectionWidget, 'data_source',
value=self.data_source,
title=_('External Data Source'),
hint=_('This will get the available items from an external source.'),
required=False)
def get_admin_attributes(self):
return WidgetField.get_admin_attributes(self) + ['items', 'show_as_radio']
return WidgetField.get_admin_attributes(self) + ['items', 'show_as_radio', 'data_source']
def check_admin_form(self, form):
items = form.get_widget('items').parse()

View File

@ -320,6 +320,12 @@ class FormDef(StorableObject):
d[field.id] = widget.parse()
if d.get(field.id) and field.convert_value_from_str:
d[field.id] = field.convert_value_from_str(d[field.id])
if d.get(field.id) and field.store_display_value:
display_value = field.store_display_value(d[field.id])
if display_value:
d['%s_display' % field.id] = display_value
elif d.has_key('%s_display' % field.id):
del d['%s_display' % field.id]
if widget and widget.cleanup:
widget.cleanup()

View File

@ -275,7 +275,12 @@ class FormStatusPage(Directory):
if not self.filled.data.has_key(f.id):
continue
value = self.filled.data[f.id]
if f.store_display_value:
value = self.filled.data['%s_display' % f.id]
else:
value = self.filled.data[f.id]
if value is None or value == '':
continue