Ticket #5050: newforms_metaclassing.patch

File newforms_metaclassing.patch, 3.3 KB (added by SmileyChris, 8 years ago)
  • django/newforms/forms.py

     
    3333    def copy(self):
    3434        return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()])
    3535
    36 class DeclarativeFieldsMetaclass(type):
     36class BaseFieldsMetaclass(type):
    3737    """
    38     Metaclass that converts Field attributes to a dictionary called
    39     'base_fields', taking into account parent class 'base_fields' as well.
     38    Metaclass that ensures attrs will have a dictionary called 'base_fields',
     39    built on the parent class 'base_fields'.
    4040    """
    4141    def __new__(cls, name, bases, attrs):
    42         fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
    43         fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
    44 
    45         # If this class is subclassing another Form, add that Form's fields.
     42        fields = attrs.get('base_fields', {}).items()
     43        # If this class is subclassing another BaseForm, add that form's fields.
    4644        # Note that we loop over the bases in *reverse*. This is necessary in
    4745        # order to preserve the correct order of fields.
    4846        for base in bases[::-1]:
    4947            if hasattr(base, 'base_fields'):
    5048                fields = base.base_fields.items() + fields
    51 
    52         attrs['base_fields'] = SortedDictFromList(fields)
     49        attrs['base_fields'] = SortedDictFromList(fields)       
    5350        return type.__new__(cls, name, bases, attrs)
    5451
     52class DeclarativeFieldsMetaclass(BaseFieldsMetaclass):
     53    """
     54    Metaclass that converts Field attributes to the dictionary attribute called
     55    'base_fields' created by BaseFieldsMetaclass.
     56    """
     57    def __new__(cls, name, bases, attrs):
     58        fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
     59        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))       
     60
     61        newcls = BaseFieldsMetaclass.__new__(cls, name, bases, attrs)
     62
     63        for k, v in fields:
     64            newcls.base_fields[k] = v
     65
     66        return newcls
     67
    5568class BaseForm(StrAndUnicode):
    5669    # This is the main implementation of all the Form logic. Note that this
    5770    # class is different than Form. See the comments by the Form class for more
    5871    # information. Any improvements to the form API should be made to *this*
    5972    # class, not to the Form class.
     73    __metaclass__ = BaseFieldsMetaclass
    6074    def __init__(self, data=None, auto_id='id_%s', prefix=None, initial=None):
    6175        self.is_bound = data is not None
    6276        self.data = data or {}
  • tests/modeltests/model_forms/models.py

     
    526526True
    527527>>> f.cleaned_data
    528528{'phone': u'312-555-1212', 'description': u'Assistance'}
     529
     530
     531# Multiple subclasses #########################################################
     532
     533>>> WriterForm = form_for_model(Writer)
     534>>> PhoneNumberForm = form_for_model(PhoneNumber)
     535>>> class MixinForm(WriterForm, PhoneNumberForm):
     536...     pass
     537>>> print MixinForm(auto_id=None).base_fields.keys()
     538['name', 'phone', 'description']
    529539"""}
Back to Top