django-form-utils / form_utils / forms.py

Carl Meyer f07174a 
Carl Meyer 0e4bae2 
Carl Meyer f07174a 
Carl Meyer 523b4b4 
Carl Meyer f07174a 




Carl Meyer ce3a724 
Carl Meyer f07174a 






Carl Meyer 19e690f 
Carl Meyer f07174a 


Carl Meyer 1c2b5bc 
Carl Meyer 19e690f 
Carl Meyer f07174a 


Carl Meyer ce3a724 





Carl Meyer f07174a 




Carl Meyer 19e690f 
Carl Meyer f07174a 
Carl Meyer 19e690f 
Carl Meyer f07174a 




Rob Hudson 3f954cf 
Carl Meyer f07174a 

Carl Meyer 135a175 
Carl Meyer f07174a 

Rob Hudson 3f954cf 













Carl Meyer f07174a 










Rob Hudson 3f954cf 



Carl Meyer f07174a 







Carl Meyer 523b4b4 






Carl Meyer f07174a 

Carl Meyer 86477db 
Carl Meyer f07174a 

Carl Meyer de93d6f 






Carl Meyer 523b4b4 








Carl Meyer 88ea3af 
Carl Meyer 523b4b4 






Carl Meyer f07174a 













Aron Griffis adfc08e 

Carl Meyer f07174a 









Carl Meyer 523b4b4 



Carl Meyer f07174a 


























Carl Meyer 9880a1e 

Carl Meyer f07174a 




Carl Meyer de93d6f 

Carl Meyer f07174a 







Carl Meyer de93d6f 

Carl Meyer f07174a 





Carl Meyer 19e690f 



Carl Meyer f07174a 
Carl Meyer de93d6f 

Carl Meyer f07174a 
Carl Meyer de93d6f 


Carl Meyer f07174a 




Rob Hudson 3f954cf 
Carl Meyer f07174a 



Rob Hudson 3f954cf 



Carl Meyer f07174a 




Carl Meyer 2a9658f 



Carl Meyer f07174a 






































"""
forms for django-form-utils

Time-stamp: <2010-04-28 02:57:16 carljm forms.py>

"""
from copy import deepcopy

from django import forms
from django.forms.util import flatatt, ErrorDict
from django.utils.safestring import mark_safe

class Fieldset(object):
    """
    An iterable Fieldset with a legend and a set of BoundFields.

    """
    def __init__(self, form, name, boundfields, legend='', classes='', description=''):
        self.form = form
        self.boundfields = boundfields
        if legend is None: legend = name
        self.legend = legend and mark_safe(legend)
        self.classes = classes
        self.description = mark_safe(description)
        self.name = name


    def _errors(self):
        return ErrorDict(((k, v) for (k, v) in self.form.errors.iteritems()
                          if k in [f.name for f in self.boundfields]))
    errors = property(_errors)

    def __iter__(self):
        for bf in self.boundfields:
            yield _mark_row_attrs(bf, self.form)

    def __repr__(self):
        return "%s('%s', %s, legend='%s', classes='%s', description='%s')" % (
            self.__class__.__name__, self.name,
            [f.name for f in self.boundfields], self.legend, self.classes, self.description)

class FieldsetCollection(object):
    def __init__(self, form, fieldsets):
        self.form = form
        self.fieldsets = fieldsets
        self._cached_fieldsets = []

    def __len__(self):
        return len(self.fieldsets) or 1

    def __iter__(self):
        if not self._cached_fieldsets:
            self._gather_fieldsets()
        for field in self._cached_fieldsets:
            yield field

    def __getitem__(self, key):
        if not self._cached_fieldsets:
            self._gather_fieldsets()
        for field in self._cached_fieldsets:
            if field.name == key:
                return field
        raise KeyError

    def _gather_fieldsets(self):
        if not self.fieldsets:
            self.fieldsets = (('main', {'fields': self.form.fields.keys(),
                                        'legend': ''}),)
        for name, options in self.fieldsets:
            try:
                field_names = [n for n in options['fields']
                               if n in self.form.fields]
            except KeyError:
                raise ValueError("Fieldset definition must include 'fields' option." )
            boundfields = [forms.forms.BoundField(self.form, self.form.fields[n], n)
                           for n in field_names]
            self._cached_fieldsets.append(Fieldset(self.form, name,
                boundfields, options.get('legend', None), 
                ' '.join(options.get('classes', ())),
                options.get('description', '')))

def _get_meta_attr(attrs, attr, default):
    try:
        ret = getattr(attrs['Meta'], attr)
    except (KeyError, AttributeError):
        ret = default
    return ret
            
def _set_meta_attr(attrs, attr, value):
    try:
        setattr(attrs['Meta'], attr, value)
        return True
    except KeyError:
        return False
            
def get_fieldsets(bases, attrs):
    """
    Get the fieldsets definition from the inner Meta class.

    """
    fieldsets = _get_meta_attr(attrs, 'fieldsets', None)
    if fieldsets is None:
        #grab the fieldsets from the first base class that has them
        for base in bases:
            fieldsets = getattr(base, 'base_fieldsets', None)
            if fieldsets is not None:
                break
    fieldsets = fieldsets or []
    return fieldsets

def get_fields_from_fieldsets(fieldsets):
    """
    Get a list of all fields included in a fieldsets definition.

    """
    fields = []
    try:
        for name, options in fieldsets:
            fields.extend(options['fields'])
    except (TypeError, KeyError):
        raise ValueError('"fieldsets" must be an iterable of two-tuples, '
                         'and the second tuple must be a dictionary '
                         'with a "fields" key')
    return fields

def get_row_attrs(bases, attrs):
    """
    Get the row_attrs definition from the inner Meta class.

    """
    return _get_meta_attr(attrs, 'row_attrs', {})

def _mark_row_attrs(bf, form):
    row_attrs = deepcopy(form._row_attrs.get(bf.name, {}))
    if bf.field.required:
        req_class = 'required'
    else:
        req_class = 'optional'
    if bf.errors:
        req_class += ' error'
    if 'class' in row_attrs:
        row_attrs['class'] = row_attrs['class'] + ' ' + req_class
    else:
        row_attrs['class'] = req_class
    bf.row_attrs = mark_safe(flatatt(row_attrs))
    return bf

class BetterFormBaseMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['base_fieldsets'] = get_fieldsets(bases, attrs)
        fields = get_fields_from_fieldsets(attrs['base_fieldsets'])
        if (_get_meta_attr(attrs, 'fields', None) is None and
            _get_meta_attr(attrs, 'exclude', None) is None):
            _set_meta_attr(attrs, 'fields', fields)
        attrs['base_row_attrs'] = get_row_attrs(bases, attrs)
        new_class = super(BetterFormBaseMetaclass,
                          cls).__new__(cls, name, bases, attrs)
        return new_class

class BetterFormMetaclass(BetterFormBaseMetaclass,
                            forms.forms.DeclarativeFieldsMetaclass):
    pass

class BetterModelFormMetaclass(BetterFormBaseMetaclass,
                                 forms.models.ModelFormMetaclass):
    pass
    
class BetterBaseForm(object):
    """
    ``BetterForm`` and ``BetterModelForm`` are subclasses of Form
    and ModelForm that allow for declarative definition of fieldsets
    and row_attrs in an inner Meta class.

    The row_attrs declaration is a dictionary mapping field names to
    dictionaries of attribute/value pairs.  The attribute/value
    dictionaries will be flattened into HTML-style attribute/values
    (i.e. {'style': 'display: none'} will become ``style="display:
    none"``), and will be available as the ``row_attrs`` attribute of
    the ``BoundField``.  Also, a CSS class of "required" or "optional"
    will automatically be added to the row_attrs of each
    ``BoundField``, depending on whether the field is required.

    There is no automatic inheritance of ``row_attrs``.
    
    The fieldsets declaration is a list of two-tuples very similar to
    the ``fieldsets`` option on a ModelAdmin class in
    ``django.contrib.admin``.

    The first item in each two-tuple is a name for the fieldset, and
    the second is a dictionary of fieldset options.

    Valid fieldset options in the dictionary include:

    ``fields`` (required): A tuple of field names to display in this
    fieldset.

    ``classes``: A list of extra CSS classes to apply to the fieldset.

    ``legend``: This value, if present, will be the contents of a ``legend``
    tag to open the fieldset.

    ``description``: A string of optional extra text to be displayed
    under the ``legend`` of the fieldset.

    When iterated over, the ``fieldsets`` attribute of a
    ``BetterForm`` (or ``BetterModelForm``) yields ``Fieldset``s.
    Each ``Fieldset`` has a ``name`` attribute, a ``legend``
    attribute, , a ``classes`` attribute (the ``classes`` tuple
    collapsed into a space-separated string), and a description
    attribute, and when iterated over yields its ``BoundField``s.

    Subclasses of a ``BetterForm`` will inherit their parent's
    fieldsets unless they define their own.

    A ``BetterForm`` or ``BetterModelForm`` can still be iterated over
    directly to yield all of its ``BoundField``s, regardless of
    fieldsets.

    """
    def __init__(self, *args, **kwargs):
        self._fieldsets = deepcopy(self.base_fieldsets)
        self._row_attrs = deepcopy(self.base_row_attrs)
        self._fieldset_collection = None
        super(BetterBaseForm, self).__init__(*args, **kwargs)

    @property
    def fieldsets(self):
        if not self._fieldset_collection:
            self._fieldset_collection = FieldsetCollection(self,
                                                           self._fieldsets)
        return self._fieldset_collection

    def __iter__(self):
        for bf in super(BetterBaseForm, self).__iter__():
            yield _mark_row_attrs(bf, self)

    def __getitem__(self, name):
        bf = super(BetterBaseForm, self).__getitem__(name)
        return _mark_row_attrs(bf, self)

class BetterForm(BetterBaseForm, forms.Form):
    __metaclass__ = BetterFormMetaclass
    __doc__ = BetterBaseForm.__doc__

class BetterModelForm(BetterBaseForm, forms.ModelForm):
    __metaclass__ = BetterModelFormMetaclass
    __doc__ = BetterBaseForm.__doc__
    

class BasePreviewForm (object):
    """
    Mixin to add preview functionality to a form.  If the form is submitted with 
    the following k/v pair in its ``data`` dictionary:
        
        'submit': 'preview'    (value string is case insensitive)
    
    Then ``PreviewForm.preview`` will be marked ``True`` and the form will
    be marked invalid (though this invalidation will not put an error in 
    its ``errors`` dictionary).
    
    """
    def __init__(self, *args, **kwargs):
        super(BasePreviewForm, self).__init__(*args, **kwargs)
        self.preview = self.check_preview(kwargs.get('data', None))
    
    def check_preview(self, data):
        if data and data.get('submit', '').lower() == u'preview':
            return True
        return False
    
    def is_valid(self, *args, **kwargs):
        if self.preview:
            return False
        return super(BasePreviewForm, self).is_valid()

class PreviewModelForm(BasePreviewForm, BetterModelForm):
    pass

class PreviewForm(BasePreviewForm, BetterForm):
    pass
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.