Ticket #5050: newforms_metaclassing.patch
File newforms_metaclassing.patch, 3.3 KB (added by , 17 years ago) |
---|
-
django/newforms/forms.py
33 33 def copy(self): 34 34 return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()]) 35 35 36 class DeclarativeFieldsMetaclass(type):36 class BaseFieldsMetaclass(type): 37 37 """ 38 Metaclass that converts Field attributes to a dictionary called39 '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'. 40 40 """ 41 41 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. 46 44 # Note that we loop over the bases in *reverse*. This is necessary in 47 45 # order to preserve the correct order of fields. 48 46 for base in bases[::-1]: 49 47 if hasattr(base, 'base_fields'): 50 48 fields = base.base_fields.items() + fields 51 52 attrs['base_fields'] = SortedDictFromList(fields) 49 attrs['base_fields'] = SortedDictFromList(fields) 53 50 return type.__new__(cls, name, bases, attrs) 54 51 52 class 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 55 68 class BaseForm(StrAndUnicode): 56 69 # This is the main implementation of all the Form logic. Note that this 57 70 # class is different than Form. See the comments by the Form class for more 58 71 # information. Any improvements to the form API should be made to *this* 59 72 # class, not to the Form class. 73 __metaclass__ = BaseFieldsMetaclass 60 74 def __init__(self, data=None, auto_id='id_%s', prefix=None, initial=None): 61 75 self.is_bound = data is not None 62 76 self.data = data or {} -
tests/modeltests/model_forms/models.py
526 526 True 527 527 >>> f.cleaned_data 528 528 {'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'] 529 539 """}