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