What is the most elegant solution to this problem:
I have a form for address information in an ecommerce application.
The user can optionally input a different delivery address - this is done
via radio button.
In this case the requirement for the delivery address fields change -
nothing special actually.
What I've done so far:
Model:
db.define_table('customer',
Field('name', requires=[IS_NOT_EMPTY()], required=True, notnull=True),
Field('company',default=None),
Field('zip', requires=[IS_MATCH('^[0-9]{5}$', error_message='not a zip
code')], required=True, notnull=True),
Field('street', requires=[IS_MATCH("[0-9a-zA-ZäöüÄÖÜ\- \.]+")],
required=True, notnull=True),
Field('city', requires=[IS_MATCH("[a-zA-ZäöüÄÖÜ\- \.]+")], required=True,
notnull=True),
Field('country', requires=[IS_IN_SET([T('Deutschland'),T('Östereich'),
T("Schweiz")])], default="Deutschland"),
Field('email',requires= [IS_NOT_EMPTY(), IS_EMAIL(),
IS_NOT_IN_DB(db,'customer.email')],
required=True, notnull=True),
Field('email_confirmation',requires= [IS_NOT_EMPTY(), IS_EMAIL(),
IS_NOT_IN_DB(db,'customer.email')],
required=True, notnull=True),
Field('delivery_address',
requires=[IS_IN_SET([T('Yes'),T('No')])],widget=SQLFORM.widgets.radio.widget,
default="No"),
Field('delivery_name',default=None),
Field('delivery_company',default=None),
Field('delivery_zip', requires=[IS_EMPTY_OR(IS_MATCH('^[0-9]{0,5}$',
error_message='not a zip code'))]),
Field('delivery_street', requires=[IS_EMPTY_OR(IS_MATCH("[a-zA-ZäöüÄÖ\-
\.]+"))],default=None),
Field('delivery_city', requires=[IS_EMPTY_OR(IS_MATCH("[a-zA-ZäöüÄÖ\-
\.]+"))],default=None),
Field('delivery_country',
requires=[IS_EMPTY_OR(IS_IN_SET([T('Deutschland'),T('Östereich'),
T("Schweiz")]))], default="Deutschland"),
Field('timestamp', 'datetime', default=request.now, readable=False,
writable=False)
)
controller:
def address():
crud.messages.submit_button = 'Weiter zur Bestätigungsseite'
crud.settings.formstyle='table2cols'
form = crud.create(db.customer)
if form.accepts(request.vars, session, onvalidation=__address_validator):
response.flash = 'form accepted'
return dict(form=form)
def __address_validator(form):
if not form.vars.email == form.vars.email_confirmation:
form.errors.email_confirmation = "Email-Adressen stimmen nicht
überein."
if form.vars.delivery_address == T("Yes"):
if not form.vars.delivery_name:
form.errors.delivery_name = "Bitte gib einen Namen ein."
if not form.vars.delivery_zip:
form.errors.delivery_zip = "Bitte gib eine Postleitzahl ein."
if not form.vars.delivery_street:
form.errors.delivery_street = "Bitte gib eine Straße mit Hausnummer
ein."
if not form.vars.delivery_city:
form.errors.delivery_city = "Bitte gib eine Stadt ein."
if not form.vars.delivery_country:
form.errors.delivery_name = "Bitte gib ein Land an."
This works! But it is not very nice to the user, because the check of the
optional fields happens after the form is accepted.
Is there a better way to set the requirements for the optional fields?
Thanks for help