Django

Code

Changeset 4506

Show
Ignore:
Timestamp:
02/14/07 17:44:46 (2 years ago)
Author:
adrian
Message:

Implemented subclassing Forms in newforms

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/newforms/forms.py

    r4504 r4506  
    3232 
    3333class DeclarativeFieldsMetaclass(type): 
    34     "Metaclass that converts Field attributes to a dictionary called 'base_fields'." 
     34    """ 
     35    Metaclass that converts Field attributes to a dictionary called 
     36    'base_fields', taking into account parent class 'base_fields' as well. 
     37    """ 
    3538    def __new__(cls, name, bases, attrs): 
    3639        fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] 
    3740        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter)) 
     41 
     42        # If this class is subclassing another Form, add that Form's fields. 
     43        # Note that we loop over the bases in *reverse*. This is necessary in 
     44        # order to preserve the correct order of fields. 
     45        for base in bases[::-1]: 
     46            if hasattr(base, 'base_fields'): 
     47                fields = base.base_fields.items() + fields 
     48 
    3849        attrs['base_fields'] = SortedDictFromList(fields) 
    3950        return type.__new__(cls, name, bases, attrs) 
  • django/trunk/docs/newforms.txt

    r4440 r4506  
    572572    '' 
    573573 
     574Subclassing forms 
     575----------------- 
     576 
     577If you subclass a custom ``Form`` class, the resulting ``Form`` class will 
     578include all fields of the parent class(es), followed by the fields you define 
     579in the subclass. 
     580 
     581In this example, ``ContactFormWithPriority`` contains all the fields from 
     582``ContactForm``, plus an additional field, ``priority``. The ``ContactForm`` 
     583fields are ordered first:: 
     584 
     585    >>> class ContactFormWithPriority(ContactForm): 
     586    ...     priority = forms.CharField() 
     587    >>> f = ContactFormWithPriority(auto_id=False) 
     588    >>> print f.as_ul() 
     589    <li>Subject: <input type="text" name="subject" maxlength="100" /></li> 
     590    <li>Message: <input type="text" name="message" /></li> 
     591    <li>Sender: <input type="text" name="sender" /></li> 
     592    <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> 
     593    <li>Priority: <input type="text" name="priority" /></li> 
     594 
     595It's possible to subclass multiple forms, treating forms as "mix-ins." In this 
     596example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm`` 
     597(in that order), and its field list includes the fields from the parent 
     598classes:: 
     599 
     600    >>> class PersonForm(Form): 
     601    ...     first_name = CharField() 
     602    ...     last_name = CharField() 
     603    >>> class InstrumentForm(Form): 
     604    ...     instrument = CharField() 
     605    >>> class BeatleForm(PersonForm, InstrumentForm): 
     606    ...     haircut_type = CharField() 
     607    >>> b = Beatle(auto_id=False) 
     608    >>> print b.as_ul() 
     609    <li>First name: <input type="text" name="first_name" /></li> 
     610    <li>Last name: <input type="text" name="last_name" /></li> 
     611    <li>Instrument: <input type="text" name="instrument" /></li> 
     612    <li>Haircut type: <input type="text" name="haircut_type" /></li> 
     613 
    574614Fields 
    575615====== 
  • django/trunk/tests/regressiontests/forms/tests.py

    r4504 r4506  
    26832683<li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li> 
    26842684 
     2685# Subclassing forms ########################################################### 
     2686 
     2687You can subclass a Form to add fields. The resulting form subclass will have 
     2688all of the fields of the parent Form, plus whichever fields you define in the 
     2689subclass. 
     2690>>> class Person(Form): 
     2691...     first_name = CharField() 
     2692...     last_name = CharField() 
     2693...     birthday = DateField() 
     2694>>> class Musician(Person): 
     2695...     instrument = CharField() 
     2696>>> p = Person(auto_id=False) 
     2697>>> print p.as_ul() 
     2698<li>First name: <input type="text" name="first_name" /></li> 
     2699<li>Last name: <input type="text" name="last_name" /></li> 
     2700<li>Birthday: <input type="text" name="birthday" /></li> 
     2701>>> m = Musician(auto_id=False) 
     2702>>> print m.as_ul() 
     2703<li>First name: <input type="text" name="first_name" /></li> 
     2704<li>Last name: <input type="text" name="last_name" /></li> 
     2705<li>Birthday: <input type="text" name="birthday" /></li> 
     2706<li>Instrument: <input type="text" name="instrument" /></li> 
     2707 
     2708Yes, you can subclass multiple forms. The fields are added in the order in 
     2709which the parent classes are listed. 
     2710>>> class Person(Form): 
     2711...     first_name = CharField() 
     2712...     last_name = CharField() 
     2713...     birthday = DateField() 
     2714>>> class Instrument(Form): 
     2715...     instrument = CharField() 
     2716>>> class Beatle(Person, Instrument): 
     2717...     haircut_type = CharField() 
     2718>>> b = Beatle(auto_id=False) 
     2719>>> print b.as_ul() 
     2720<li>First name: <input type="text" name="first_name" /></li> 
     2721<li>Last name: <input type="text" name="last_name" /></li> 
     2722<li>Birthday: <input type="text" name="birthday" /></li> 
     2723<li>Instrument: <input type="text" name="instrument" /></li> 
     2724<li>Haircut type: <input type="text" name="haircut_type" /></li> 
     2725 
    26852726# Forms with prefixes ######################################################### 
    26862727