Ptah Forms¶
ptah.form is an optional form library package. It provides some benefits when using it with the integrated environment such as autogeneration of forms for models, validation using the sqlalchemy constraints, and JSON representations for the REST api.
Form¶
Supports HTML generation, CSRF protection, additional field validation.
Form Validation¶
The default form validation uses CSRF prtoection to validate data input.
Fieldset¶
A ordered dictionary of Field instances. Fieldset supports validation and extraction.
Fieldset Validation¶
Is used when you have validation dependencies between Fields. For instance if Field Y depends
Fieldset Extraction¶
Internal implementation details and only needed for expert usage. Possibly needs renaming or refactoring.
Field¶
Fields are important in Ptah not only because its how forms are used in the HTML interface but they are also used in the REST interface. For instance when you send update via HTTP (html POST or json POST) the same field implementation is used for deserialization and validation.
Field Serialization¶
- serialize converts the field and data python structure into string representation. e.g. dattime.date(2011, 12, 12) into ‘2011-12-12’.
- deserailize converts a string representation into the internal representation. e.g. 2011-12-12 into datetime.date(2011, 12, 12)
Field Modes¶
Display mode and input mode.
Field Validation¶
Specific validation rules or whether a field is required is validated through the field validation.
1 2 3 4 5 6 7 | TELEPHONE_REGEX = u'^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$'
class Telephone(form.Regex):
""" Telephone number validator """
def __init__(self, msg=None):
if msg is None:
msg = "Invalid telephone number"
super(Telephone, self).__init__(TELEPHONE_REGEX, msg=msg)
|
A ptah.form.Field accepts a validator in its constructor. The fields’ validator will be called by the form with both field and value as parameters.
1 2 3 4 5 | form.TextField(
'phone',
title = u'Telephone number',
description=u'Please provide telephone number',
validator = Telephone()),
|
Field Extraction¶
Extracts the value from request.
Field Factory¶
Expert level usage. This is how Ptah’s internals work.
Examples¶
There are 2 form examples which can be found in ptah_models package in the examples repository. You can find both examples in ptah_models/views.py.
Manual Form & Fieldset¶
The contact-us form in ptah_models.
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 | contactform = form.Form(context, request)
contactform.fields = form.Fieldset(
form.TextField(
'fullname',
title = u'First & Last Name'),
form.TextField(
'phone',
title = u'Telephone number',
description=u'Please provide telephone number',
validator = Telephone()),
form.TextField(
'email',
title = u'Your email',
description = u'Please provide email address.',
validator = form.Email()),
form.TextAreaField(
'subject',
title = u'How can we help?',
missing = u''),
)
# form actions
def cancelAction(form):
return HTTPFound(location='/')
def updateAction(form):
data, errors = form.extract()
if errors:
form.message(errors, 'form-error')
return
# form.context is ...
form.context.fullname = data['fullname']
form.context.phone = data['phone']
form.context.email = data['email']
form.context.subject = data['subject']
# You would add any logic/database updates/insert here.
# You would probably also redirect.
log.info('The form was updated successfully')
form.message('The form was updated successfully')
contactform.label = u'Contact us'
contactform.buttons.add_action('Update', action=updateAction)
contactform.buttons.add_action('Cancel', action=cancelAction)
# form default values
contactform.content = {}
# compute the form
result = contactform.update()
if isinstance(result, HTTPFound):
return result
# generate HTML from form
html = contactform.render()
|
Manual Form & Auto-Fieldset¶
In the ptah_models package there is a content model, Link. This model can
be found in ptah_models/models.py
. This code-snippet is found in
the ptah_models/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 | linkform = form.Form(context,request)
linkform.fields = models.Link.__type__.fieldset
def cancelAction(form):
return HTTPFound(location='/')
def updateAction(form):
data, errors = form.extract()
if errors:
form.message(errors, 'form-error')
return
link = models.Link(title = data['title'],
href = data['href'],
color = data['color'])
ptah.get_session().add(link)
form.message('Link has been created.')
return HTTPFound(location='/')
linkform.label = u'Add link'
linkform.buttons.add_action('Add', action=updateAction)
linkform.buttons.add_action('Cancel', action=cancelAction)
result = linkform.update() # prepare form for rendering
if isinstance(result, HTTPFound):
return result
rendered_form = linkform.render()
|
Everything Manual¶
Using form without context and request.
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 | from ptah import form
from ptah_models.models import Link
def action1(form):
print ('action1', form)
def action2(form):
print ('action2', form)
eform = form.Form(None, None)
eform.params = {}
eform.method = 'params'
eform.fields = Link.__type__.fieldset
eform.buttons.add_action('Test submit', name='ac1', action=action1)
eform.buttons.add_action('Test action2', name='ac2', action=action2)
print "==== execute action1 ===="
eform.params = {'%sbuttons.ac1'%eform.prefix: 'value'}
eform.update()
print
print "==== extract data ====="
data, errors = eform.extract()
print
print "DATA:"
pprint(data)
print
print "ERRORS:"
pprint(errors)
|
Class-based Form¶
Example of subclassing ptah.form.Form.