I need to generate my fields in the constructor of the form since the number of fields needed can vary. I think my current solution is the problem. I get an exception when I try to expand the form in my template saying
AttributeError: 'UnboundField' object has no attribute 'call'
What is wrong with this code?
class DriverTemplateSchedueForm(Form):
def __init__(self, per_day=30, **kwargs):
self.per_day = per_day
ages = model.Agency.query.all()
ages = [(a.id, a.name) for a in ages]
self.days = [[[]] * per_day] * 7
for d in range(7):
for i in range(per_day):
lbl = 'item_' + str(d) + '_' + str(i)
self.__dict__[lbl] = SelectField(lbl, choices=ages)
self.days[d][i] = self.__dict__[lbl]
for day in self.days:
print(day)
Form.__init__(self, **kwargs)
The validate_on_submit() method of the form returns True when the form was submitted and the data was accepted by all the field validators. In all other cases, validate_on_submit() returns False . The return value of this method effectively serves to determine whether the form needs to be rendered or processed.
WTF stands for WT Forms which is intended to provide the interactive user interface for the user. The WTF is a built-in module of the flask which provides an alternative way of designing forms in the flask web applications.
StringField (default field arguments)[source] This field is the base for most of the more complicated fields, and represents an <input type="text"> .
You need to add the fields to your class not your instance:
def driver_template_schedue_form(ages, per_day=30, **kwargs):
"""Dynamically creates a driver's schedule form"""
# First we create the base form
# Note that we are not adding any fields to it yet
class DriverTemplateScheduleForm(Form):
pass
# Then we iterate over our ranges
# and create a select field for each
# item_{d}_{i} in the set, setting each field
# *on our **class**.
for d in range(7):
for i in range(per_day):
label = 'item_{:d}_{:d}'.format(d, i)
field = SelectField(label, choices=ages)
setattr(DriverTemplateScheduleForm, label, field)
# Finally, we return the *instance* of the class
# We could also use a dictionary comprehension and then use
# `type` instead, if that seemed clearer. That is:
# type('DriverTemplateScheduleForm', Form, our_fields)(**kwargs)
return DriverTemplateScheduleForm(**kwargs)
self
work?WTForms uses meta-classes to register forms and fields together and preserve order. *Field
instances are created unbound, added to the Form
class' _unbound_fields
attribute and are bound to the class instance when the class is being constructed by the meta-class.
By the time DriverTemplateScheduleForm.__init__
is run, _unbound_fields
has already been populated. You can push your fields into self._unbound_fields
and things would also just work, but that's making use of a private API and so may break later.
The answer about meta-class is right, but in case if you really need this (like I do):
class SomeForm(Form):
def __init__(self, *args, **kwargs):
for name in kwargs.keys():
if name.startswith('PREFIX_'):
field = HiddenField()
setattr(self, name, field)
self._unbound_fields = self._unbound_fields + [[name, field]]
super(SomeForm, self).__init__(*args, **kwargs)
Note that we're not modifying _unbound_fields
, not to have this fields in form class next time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With