More ValidatorsΒΆ

We have a strong basis in place now:

  • A sample application that lists people, along with add/edit/view person
  • Validators from FormEncode and markup from ZPT

We can now explore some other validators and patterns:

  • ``is_cancelled`` support. Forms should have a cancel button that bails out on the form and takes you back to the parent.
  • Confirm password. Have a password field with a minimal length that must match another field.
  1. The t3/baseform.py:

     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
    97
    """Base class for KARL3 forms.
    """
    
    from lxml.html import document_fromstring
    from lxml.html import tostring
    from time import time
    from formencode import Schema
    from formencode import Invalid
    from copy import deepcopy
    
    # Simulate getting some vocabularies
    vocabularies = {
        'countries': [
            ('AT', 'Austria'),
            ('BE', 'Belgium'),
            ('CA', 'Canada'),
            ('DE', 'Germany'),
            ('ES', 'Estonia'),
            ('FI', 'Finland'),
            ('GB', 'Great Britain'),
            ],
        }
    
    # Make some re-usable fields
    from formencode import validators
    name = validators.UnicodeString(not_empty=True)
    age = validators.Int(not_empty=True, max=200, default=93)
    country = validators.OneOf([i[0] for i in vocabularies['countries']])
    password = validators.UnicodeString(not_empty=True, strip=True, min=8)
    password_confirm = validators.UnicodeString(
        not_empty=True, strip=True, min=8)
    chained_validators = [validators.FieldsMatch(
            'password', 'password_confirm')]
    
    
    class BaseForm(Schema):
    
        submit_name = 'form.submitted'
        cancel_name = 'form.cancel'
        allow_extra_fields = True
        filter_extra_fields = True
    
        def __init__(self):
            Schema.__init__(self)
            self.defaults = {}
            for name, value in self.fields.items():
                default = getattr(value, 'default', None)
                if default is not None:
                    self.defaults[name] = value.default
                
    
        def is_cancelled(self, request):
            self.start_time = time()
            return request.POST.get(self.cancel_name, False)
    
        def is_submitted(self, request):
            return request.POST.get(self.submit_name, False)
    
        def validate(self, fieldvalues):
            fielderrors = {}
            try:
                fieldvalues = self.to_python(fieldvalues)
            except Invalid, e:
                fielderrors = e.error_dict
    
            return fieldvalues, fielderrors
    
    
        def merge(self, htmlstring, fieldvalues):
            # Merge in field values, either from the default or from what
            # they typed in.
    
            form_tree = document_fromstring(htmlstring)
            form = form_tree.forms[0]
    
            schema_field_names = self.fields.keys()
            for field_name, field_value in fieldvalues.items():
                if field_name in schema_field_names:
                    form.fields[field_name] = unicode(field_value)
            merged_form_html = tostring(form)
    
            # Record the elapsed time
            self.elapsed = str(1 / (time() - self.start_time))[0:7]
    
            return merged_form_html
    
        def combine_dicts(self, dict1, dict2):
            # We often have multiple sources for field values.  For
            # example, the default defined into the field versus the value
            # typed into the request.params.  Combine these, with the
            # latter taking presence over the former.
    
            fieldvalues = deepcopy(dict1)
            for key, value in dict2.items():
                fieldvalues[key] = value
    
            return fieldvalues
    
  2. The views at t3/views.py:

      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
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    from repoze.bfg.chameleon_zpt import render_template_to_response
    from repoze.bfg.chameleon_zpt import get_template
    from repoze.bfg.chameleon_zpt import render_template
    from repoze.bfg.view import static
    from webob.exc import HTTPFound
    from repoze.bfg.url import model_url
    
    from baseform import BaseForm
    from baseform import name
    from baseform import age
    from baseform import country
    from baseform import password
    from baseform import password_confirm
    from baseform import chained_validators
    from baseform import vocabularies
    
    from t3.models import Person
    from formencode import Invalid
    
    from random import randrange
    
    static_view = static('templates/static')
    
    # Define a form schema, make an instance
    class MyInfo(BaseForm):
        name = name
        age = age
        country = country
        password = password
        password_confirm = password_confirm
        chained_validators = chained_validators
    myinfo = MyInfo
    
    def list_people_view(context, request):
    
        layout = get_template('templates/layout.pt')
    
        return render_template_to_response(
            'templates/list_people.pt',
            context = context,
            request = request,
            page_title='List People',
            layout=layout,
            )
    
    def add_person_view(context, request):
    
        layout = get_template('templates/layout.pt')
    
        formfields = get_template('templates/formfields.pt')
        form = myinfo()
    
        if form.is_cancelled(request):
            return HTTPFound(location=model_url(context, request))
    
        if form.is_submitted(request):
            fieldvalues = form.combine_dicts(form.defaults, request.POST)
            # Now validate
            try:
                fv = fieldvalues = form.to_python(fieldvalues)
                fielderrors = {}
    
                # Go ahead and do the work to add content, etc.
                person = Person(fv['name'], fv['age'], fv['country'])
                __name__ = str(randrange(0, 99999))
                context[__name__] = person
                return HTTPFound(location=model_url(person, request))
    
            except Invalid, e:
                fielderrors = e.error_dict
    
        else:
            fieldvalues = form.defaults
            fielderrors = {}
    
        # Render the form and shove some default values in
        form_html = render_template(
            'templates/myform.pt',
            context = context,
            request=request,
            formfields=formfields,
            fielderrors=fielderrors,
            vocabularies=vocabularies,
            )
        rendered_form = form.merge(form_html, fieldvalues)
    
        return render_template_to_response(
            'templates/add_person.pt',
            context=context,
            request = request,
            page_title='Add Person',
            layout=layout,
            form_html=rendered_form,
            elapsed=form.elapsed,
            )
    
    def show_person_view(context, request):
    
        layout = get_template('templates/layout.pt')
    
        return render_template_to_response(
            'templates/show_person.pt',
            context = context,
            request = request,
            page_title='Show Person',
            layout=layout,
            )
    
    def edit_person_view(context, request):
    
        layout = get_template('templates/layout.pt')
    
        formfields = get_template('templates/formfields.pt')
        form = myinfo()
    
        if form.is_cancelled(request):
            return HTTPFound(location=model_url(context, request))
    
        if form.is_submitted(request):
            fieldvalues = form.combine_dicts(context.__dict__, request.POST)
    
            # Now validate
            try:
                fieldvalues = form.to_python(fieldvalues)
                fielderrors = {}
    
                # Go ahead and do the work to update content, etc.
                context.name = fieldvalues['name']
                context.age = fieldvalues['age']
                context.country = fieldvalues['country']
                return HTTPFound(location=model_url(context, request))
    
            except Invalid, e:
                fielderrors = e.error_dict
    
        else:
            fieldvalues = context.__dict__
            fielderrors = {}
    
        # Render the form and shove some default values in
        form_html = render_template(
            'templates/myform.pt',
            request=request,
            formfields=formfields,
            fielderrors=fielderrors,
            vocabularies=vocabularies,
            )
        rendered_form = form.merge(form_html, fieldvalues)
    
        return render_template_to_response(
            'templates/edit_person.pt',
            context = context,
            request = request,
            page_title='Edit %s' % context.name,
            layout=layout,
            form_html=rendered_form,
            elapsed=form.elapsed,
            )
    

Previous topic

Refactor Into Models

Next topic

Notes for the Tutorial

This Page