- Author:
- stephen_mcd
- Posted:
- February 24, 2010
- Language:
- Python
- Version:
- 1.1
- Score:
- 2 (after 2 ratings)
Template designers often require access to individual form fields or sets of form fields to control complex form layouts. While this is possible via looping through form fields in the template it can lead to ugly logic inside templates as well as losing the ability to use the as_* form rendering methods.
This class when mixed into a form class provides hooks for template designers to access individual fields or sets of fields based on various criteria such as field name prefix or fields appearing before or after certain fields in the form, while still being able to use the as_* form rendering methods against these fields.
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 | """
This class when mixed into a form class provides hooks for template designers to
access individual fields or sets of fields based on various criteria such as field
name prefix or fields appearing before or after certain fields in the form, while
still being able to use the as_* form rendering methods against these fields.
Credits:
--------
Stephen McDonald <[email protected]>
License:
--------
Creative Commons Attribution-Share Alike 3.0 License
http://creativecommons.org/licenses/by-sa/3.0/
When attributing this work, you must maintain the Credits
paragraph above.
"""
from copy import copy
from itertools import dropwhile, takewhile
from re import match
from django.utils.datastructures import SortedDict
class FormsetForm(object):
"""
Form mixin that gives template designers greater control over form field
rendering while still using the as_* methods. The following methods return
a copy of the form with only a subset of fields that can then be rendered
with as_* methods.
{{ form.PREFIX_fields.as_* }} - fields with a name starting with PREFIX
{{ form.FIELD_field.as_* }} - a single field with the name FIELD
{{ form.fields_before_FIELD.as_* }} - fields before the field named FIELD
{{ form.fields_after_FIELD.as_* }} - fields after the field named FIELD
{{ form.other_fields.as_* }} - fields not yet accessed as a formset
CSS classes are also added to the rendered fields. These are the lowercase
classname of the widget, eg "textinput" or "checkboxinput", and if the field
is required the class of "required" is also added.
"""
def _fieldset(self, field_names):
"""
Return a subset of fields by making a copy of the form containing only
the given field names and adding extra CSS classes to the fields.
"""
fieldset = copy(self)
if not hasattr(self, "_fields_done"):
self._fields_done = []
else:
# all fieldsets will contain all non-field errors, so for fieldsets
# other than the first ensure the call to non-field errors does nothing
fieldset.non_field_errors = lambda *args: None
field_names = filter(lambda f: f not in self._fields_done, field_names)
fieldset.fields = SortedDict([(f, self.fields[f]) for f in field_names])
for field in fieldset.fields.values():
field.widget.attrs["class"] = field.widget.__class__.__name__.lower()
if field.required:
field.widget.attrs["class"] += " required"
self._fields_done.extend(field_names)
return fieldset
def __getattr__(self, name):
"""
Dynamic fieldset caller - matches requested attribute name against
pattern for creating the list of field names to use for the fieldset.
"""
filters = (
("^other_fields$", lambda:
self.fields.keys()),
("^(\w*)_fields$", lambda name:
[f for f in self.fields.keys() if f.startswith(name)]),
("^(\w*)_field$", lambda name:
[f for f in self.fields.keys() if f == name]),
("^fields_before_(\w*)$", lambda name:
takewhile(lambda f: f != name, self.fields.keys())),
("^fields_after_(\w*)$", lambda name:
list(dropwhile(lambda f: f != name, self.fields.keys()))[1:]),
)
for filter_exp, filter_func in filters:
filter_args = match(filter_exp, name)
if filter_args is not None:
return self._fieldset(filter_func(*filter_args.groups()))
raise AttributeError(name)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.