Implemented subclassing Forms in newforms
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4c4209b144
commit
0518205308
|
@ -31,10 +31,21 @@ class SortedDictFromList(SortedDict):
|
||||||
return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()])
|
return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()])
|
||||||
|
|
||||||
class DeclarativeFieldsMetaclass(type):
|
class DeclarativeFieldsMetaclass(type):
|
||||||
"Metaclass that converts Field attributes to a dictionary called 'base_fields'."
|
"""
|
||||||
|
Metaclass that converts Field attributes to a dictionary called
|
||||||
|
'base_fields', taking into account parent class 'base_fields' as well.
|
||||||
|
"""
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
|
fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
|
||||||
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
|
fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
|
||||||
|
|
||||||
|
# If this class is subclassing another Form, add that Form's fields.
|
||||||
|
# Note that we loop over the bases in *reverse*. This is necessary in
|
||||||
|
# order to preserve the correct order of fields.
|
||||||
|
for base in bases[::-1]:
|
||||||
|
if hasattr(base, 'base_fields'):
|
||||||
|
fields = base.base_fields.items() + fields
|
||||||
|
|
||||||
attrs['base_fields'] = SortedDictFromList(fields)
|
attrs['base_fields'] = SortedDictFromList(fields)
|
||||||
return type.__new__(cls, name, bases, attrs)
|
return type.__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
|
|
|
@ -571,6 +571,46 @@ is a list-like object that is displayed as an HTML ``<ul>`` when printed::
|
||||||
>>> str(f['subject'].errors)
|
>>> str(f['subject'].errors)
|
||||||
''
|
''
|
||||||
|
|
||||||
|
Subclassing forms
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If you subclass a custom ``Form`` class, the resulting ``Form`` class will
|
||||||
|
include all fields of the parent class(es), followed by the fields you define
|
||||||
|
in the subclass.
|
||||||
|
|
||||||
|
In this example, ``ContactFormWithPriority`` contains all the fields from
|
||||||
|
``ContactForm``, plus an additional field, ``priority``. The ``ContactForm``
|
||||||
|
fields are ordered first::
|
||||||
|
|
||||||
|
>>> class ContactFormWithPriority(ContactForm):
|
||||||
|
... priority = forms.CharField()
|
||||||
|
>>> f = ContactFormWithPriority(auto_id=False)
|
||||||
|
>>> print f.as_ul()
|
||||||
|
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
|
||||||
|
<li>Message: <input type="text" name="message" /></li>
|
||||||
|
<li>Sender: <input type="text" name="sender" /></li>
|
||||||
|
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
|
||||||
|
<li>Priority: <input type="text" name="priority" /></li>
|
||||||
|
|
||||||
|
It's possible to subclass multiple forms, treating forms as "mix-ins." In this
|
||||||
|
example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm``
|
||||||
|
(in that order), and its field list includes the fields from the parent
|
||||||
|
classes::
|
||||||
|
|
||||||
|
>>> class PersonForm(Form):
|
||||||
|
... first_name = CharField()
|
||||||
|
... last_name = CharField()
|
||||||
|
>>> class InstrumentForm(Form):
|
||||||
|
... instrument = CharField()
|
||||||
|
>>> class BeatleForm(PersonForm, InstrumentForm):
|
||||||
|
... haircut_type = CharField()
|
||||||
|
>>> b = Beatle(auto_id=False)
|
||||||
|
>>> print b.as_ul()
|
||||||
|
<li>First name: <input type="text" name="first_name" /></li>
|
||||||
|
<li>Last name: <input type="text" name="last_name" /></li>
|
||||||
|
<li>Instrument: <input type="text" name="instrument" /></li>
|
||||||
|
<li>Haircut type: <input type="text" name="haircut_type" /></li>
|
||||||
|
|
||||||
Fields
|
Fields
|
||||||
======
|
======
|
||||||
|
|
||||||
|
|
|
@ -2682,6 +2682,47 @@ purposes, though.
|
||||||
<li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li>
|
<li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li>
|
||||||
<li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li>
|
<li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li>
|
||||||
|
|
||||||
|
# Subclassing forms ###########################################################
|
||||||
|
|
||||||
|
You can subclass a Form to add fields. The resulting form subclass will have
|
||||||
|
all of the fields of the parent Form, plus whichever fields you define in the
|
||||||
|
subclass.
|
||||||
|
>>> class Person(Form):
|
||||||
|
... first_name = CharField()
|
||||||
|
... last_name = CharField()
|
||||||
|
... birthday = DateField()
|
||||||
|
>>> class Musician(Person):
|
||||||
|
... instrument = CharField()
|
||||||
|
>>> p = Person(auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>First name: <input type="text" name="first_name" /></li>
|
||||||
|
<li>Last name: <input type="text" name="last_name" /></li>
|
||||||
|
<li>Birthday: <input type="text" name="birthday" /></li>
|
||||||
|
>>> m = Musician(auto_id=False)
|
||||||
|
>>> print m.as_ul()
|
||||||
|
<li>First name: <input type="text" name="first_name" /></li>
|
||||||
|
<li>Last name: <input type="text" name="last_name" /></li>
|
||||||
|
<li>Birthday: <input type="text" name="birthday" /></li>
|
||||||
|
<li>Instrument: <input type="text" name="instrument" /></li>
|
||||||
|
|
||||||
|
Yes, you can subclass multiple forms. The fields are added in the order in
|
||||||
|
which the parent classes are listed.
|
||||||
|
>>> class Person(Form):
|
||||||
|
... first_name = CharField()
|
||||||
|
... last_name = CharField()
|
||||||
|
... birthday = DateField()
|
||||||
|
>>> class Instrument(Form):
|
||||||
|
... instrument = CharField()
|
||||||
|
>>> class Beatle(Person, Instrument):
|
||||||
|
... haircut_type = CharField()
|
||||||
|
>>> b = Beatle(auto_id=False)
|
||||||
|
>>> print b.as_ul()
|
||||||
|
<li>First name: <input type="text" name="first_name" /></li>
|
||||||
|
<li>Last name: <input type="text" name="last_name" /></li>
|
||||||
|
<li>Birthday: <input type="text" name="birthday" /></li>
|
||||||
|
<li>Instrument: <input type="text" name="instrument" /></li>
|
||||||
|
<li>Haircut type: <input type="text" name="haircut_type" /></li>
|
||||||
|
|
||||||
# Forms with prefixes #########################################################
|
# Forms with prefixes #########################################################
|
||||||
|
|
||||||
Sometimes it's necessary to have multiple forms display on the same HTML page,
|
Sometimes it's necessary to have multiple forms display on the same HTML page,
|
||||||
|
|
Loading…
Reference in New Issue