1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
import operator
from wtforms import fields, widgets
from wtforms.validators import ValidationError
anyjson = None
try:
import anyjson
except ImportError:
pass
class ImproperlyConfigured(Exception):
pass
class AjaxField(fields.Field):
widget = widgets.HiddenInput()
def __init__(
self,
label=None,
validators=None,
data_url=None,
get_object=None,
get_pk=None,
coerce=int,
get_label=None,
allow_blank=False,
blank_text="",
**kwargs,
):
super().__init__(label, validators, **kwargs)
if anyjson is None:
raise ImproperlyConfigured(
"AjaxField requires anyjson extension to be installed."
)
if data_url is None:
raise Exception("data_url must be given")
self.get_pk = get_pk
if get_label is None:
self.get_label = lambda x: x
elif isinstance(get_label, str):
self.get_label = operator.attrgetter(get_label)
else:
self.get_label = get_label
self.coerce = coerce
self.data_url = data_url
self.get_object = get_object
self.allow_blank = allow_blank
self.blank_text = blank_text
@property
def data(self):
if self._formdata is not None:
try:
pk = self.coerce(self._formdata)
except ValueError:
self.data = None
else:
self.data = self.get_object(pk)
return self._data
@data.setter
def data(self, data):
self._data = data
self._formdata = None
def process_formdata(self, valuelist):
if valuelist:
if self.allow_blank and not valuelist[0]:
self.data = None
else:
self._data = None
self._formdata = valuelist[0]
def pre_validate(self, form):
if self.data is None:
if self._formdata or not self.allow_blank:
raise ValidationError("Not a valid choice")
def __call__(self, **kwargs):
kwargs.setdefault("data-allow-clear", anyjson.serialize(self.allow_blank))
kwargs.setdefault("data-placeholder", self.blank_text)
kwargs.setdefault("data-url", self.data_url)
if self.data is not None:
kwargs.setdefault("data-initial-label", self.get_label(self.data))
kwargs.setdefault("value", self.get_pk(self.data))
else:
kwargs.setdefault("value", "")
return super().__call__(**kwargs)
|