216 lines
7.4 KiB
Python
216 lines
7.4 KiB
Python
from __future__ import unicode_literals
|
|
|
|
import decimal
|
|
import operator
|
|
|
|
from wtforms import fields, widgets
|
|
from wtforms.compat import text_type, string_types
|
|
|
|
|
|
class ReferencePropertyField(fields.SelectFieldBase):
|
|
"""
|
|
A field for ``db.ReferenceProperty``. The list items are rendered in a
|
|
select.
|
|
|
|
:param reference_class:
|
|
A db.Model class which will be used to generate the default query
|
|
to make the list of items. If this is not specified, The `query`
|
|
property must be overridden before validation.
|
|
:param get_label:
|
|
If a string, use this attribute on the model class as the label
|
|
associated with each option. If a one-argument callable, this callable
|
|
will be passed model instance and expected to return the label text.
|
|
Otherwise, the model object's `__str__` or `__unicode__` will be used.
|
|
:param allow_blank:
|
|
If set to true, a blank choice will be added to the top of the list
|
|
to allow `None` to be chosen.
|
|
:param blank_text:
|
|
Use this to override the default blank option's label.
|
|
"""
|
|
widget = widgets.Select()
|
|
|
|
def __init__(self, label=None, validators=None, reference_class=None,
|
|
get_label=None, allow_blank=False,
|
|
blank_text='', **kwargs):
|
|
super(ReferencePropertyField, self).__init__(label, validators,
|
|
**kwargs)
|
|
if get_label is None:
|
|
self.get_label = lambda x: x
|
|
elif isinstance(get_label, string_types):
|
|
self.get_label = operator.attrgetter(get_label)
|
|
else:
|
|
self.get_label = get_label
|
|
|
|
self.allow_blank = allow_blank
|
|
self.blank_text = blank_text
|
|
self._set_data(None)
|
|
if reference_class is not None:
|
|
self.query = reference_class.all()
|
|
|
|
def _get_data(self):
|
|
if self._formdata is not None:
|
|
for obj in self.query:
|
|
if str(obj.key()) == self._formdata:
|
|
self._set_data(obj)
|
|
break
|
|
return self._data
|
|
|
|
def _set_data(self, data):
|
|
self._data = data
|
|
self._formdata = None
|
|
|
|
data = property(_get_data, _set_data)
|
|
|
|
def iter_choices(self):
|
|
if self.allow_blank:
|
|
yield ('__None', self.blank_text, self.data is None)
|
|
|
|
for obj in self.query:
|
|
key = str(obj.key())
|
|
label = self.get_label(obj)
|
|
yield (key, label, (self.data.key() == obj.key()) if self.data else False)
|
|
|
|
def process_formdata(self, valuelist):
|
|
if valuelist:
|
|
if valuelist[0] == '__None':
|
|
self.data = None
|
|
else:
|
|
self._data = None
|
|
self._formdata = valuelist[0]
|
|
|
|
def pre_validate(self, form):
|
|
if not self.allow_blank or self.data is not None:
|
|
for obj in self.query:
|
|
if str(self.data.key()) == str(obj.key()):
|
|
break
|
|
else:
|
|
raise ValueError(self.gettext('Not a valid choice'))
|
|
|
|
|
|
class KeyPropertyField(fields.SelectFieldBase):
|
|
"""
|
|
A field for ``ndb.KeyProperty``. The list items are rendered in a select.
|
|
|
|
:param reference_class:
|
|
A db.Model class which will be used to generate the default query
|
|
to make the list of items. If this is not specified, The `query`
|
|
property must be overridden before validation.
|
|
:param get_label:
|
|
If a string, use this attribute on the model class as the label
|
|
associated with each option. If a one-argument callable, this callable
|
|
will be passed model instance and expected to return the label text.
|
|
Otherwise, the model object's `__str__` or `__unicode__` will be used.
|
|
:param allow_blank:
|
|
If set to true, a blank choice will be added to the top of the list
|
|
to allow `None` to be chosen.
|
|
:param blank_text:
|
|
Use this to override the default blank option's label.
|
|
"""
|
|
widget = widgets.Select()
|
|
|
|
def __init__(self, label=None, validators=None, reference_class=None,
|
|
get_label=None, allow_blank=False, blank_text='', **kwargs):
|
|
super(KeyPropertyField, self).__init__(label, validators, **kwargs)
|
|
if get_label is None:
|
|
self.get_label = lambda x: x
|
|
elif isinstance(get_label, basestring):
|
|
self.get_label = operator.attrgetter(get_label)
|
|
else:
|
|
self.get_label = get_label
|
|
|
|
self.allow_blank = allow_blank
|
|
self.blank_text = blank_text
|
|
self._set_data(None)
|
|
if reference_class is not None:
|
|
self.query = reference_class.query()
|
|
|
|
def _get_data(self):
|
|
if self._formdata is not None:
|
|
for obj in self.query:
|
|
if str(obj.key.id()) == self._formdata:
|
|
self._set_data(obj)
|
|
break
|
|
return self._data
|
|
|
|
def _set_data(self, data):
|
|
self._data = data
|
|
self._formdata = None
|
|
|
|
data = property(_get_data, _set_data)
|
|
|
|
def iter_choices(self):
|
|
if self.allow_blank:
|
|
yield ('__None', self.blank_text, self.data is None)
|
|
|
|
for obj in self.query:
|
|
key = str(obj.key.id())
|
|
label = self.get_label(obj)
|
|
yield (key, label, (self.data.key == obj.key) if self.data else False)
|
|
|
|
def process_formdata(self, valuelist):
|
|
if valuelist:
|
|
if valuelist[0] == '__None':
|
|
self.data = None
|
|
else:
|
|
self._data = None
|
|
self._formdata = valuelist[0]
|
|
|
|
def pre_validate(self, form):
|
|
if self.data is not None:
|
|
for obj in self.query:
|
|
if self.data.key == obj.key:
|
|
break
|
|
else:
|
|
raise ValueError(self.gettext('Not a valid choice'))
|
|
elif not self.allow_blank:
|
|
raise ValueError(self.gettext('Not a valid choice'))
|
|
|
|
|
|
class StringListPropertyField(fields.TextAreaField):
|
|
"""
|
|
A field for ``db.StringListProperty``. The list items are rendered in a
|
|
textarea.
|
|
"""
|
|
def _value(self):
|
|
if self.raw_data:
|
|
return self.raw_data[0]
|
|
else:
|
|
return self.data and text_type("\n".join(self.data)) or ''
|
|
|
|
def process_formdata(self, valuelist):
|
|
if valuelist:
|
|
try:
|
|
self.data = valuelist[0].splitlines()
|
|
except ValueError:
|
|
raise ValueError(self.gettext('Not a valid list'))
|
|
|
|
|
|
class IntegerListPropertyField(fields.TextAreaField):
|
|
"""
|
|
A field for ``db.StringListProperty``. The list items are rendered in a
|
|
textarea.
|
|
"""
|
|
def _value(self):
|
|
if self.raw_data:
|
|
return self.raw_data[0]
|
|
else:
|
|
return text_type('\n'.join(self.data)) if self.data else ''
|
|
|
|
def process_formdata(self, valuelist):
|
|
if valuelist:
|
|
try:
|
|
self.data = [int(value) for value in valuelist[0].splitlines()]
|
|
except ValueError:
|
|
raise ValueError(self.gettext('Not a valid integer list'))
|
|
|
|
|
|
class GeoPtPropertyField(fields.TextField):
|
|
|
|
def process_formdata(self, valuelist):
|
|
if valuelist:
|
|
try:
|
|
lat, lon = valuelist[0].split(',')
|
|
self.data = '%s,%s' % (decimal.Decimal(lat.strip()), decimal.Decimal(lon.strip()),)
|
|
except (decimal.InvalidOperation, ValueError):
|
|
raise ValueError('Not a valid coordinate location')
|