Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Implemented subclassing Forms in newforms

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4506 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 05182053088d3c30fad3fe5cc81db7a12412ae2b 1 parent 4c4209b
Adrian Holovaty authored February 14, 2007
13  django/newforms/forms.py
@@ -31,10 +31,21 @@ def copy(self):
31 31
         return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()])
32 32
 
33 33
 class 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
+    """
35 38
     def __new__(cls, name, bases, attrs):
36 39
         fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
37 40
         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
+
38 49
         attrs['base_fields'] = SortedDictFromList(fields)
39 50
         return type.__new__(cls, name, bases, attrs)
40 51
 
40  docs/newforms.txt
@@ -571,6 +571,46 @@ is a list-like object that is displayed as an HTML ``<ul>`` when printed::
571 571
     >>> str(f['subject'].errors)
572 572
     ''
573 573
 
  574
+Subclassing forms
  575
+-----------------
  576
+
  577
+If you subclass a custom ``Form`` class, the resulting ``Form`` class will
  578
+include all fields of the parent class(es), followed by the fields you define
  579
+in the subclass.
  580
+
  581
+In this example, ``ContactFormWithPriority`` contains all the fields from
  582
+``ContactForm``, plus an additional field, ``priority``. The ``ContactForm``
  583
+fields 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
+
  595
+It's possible to subclass multiple forms, treating forms as "mix-ins." In this
  596
+example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm``
  597
+(in that order), and its field list includes the fields from the parent
  598
+classes::
  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
+
574 614
 Fields
575 615
 ======
576 616
 
41  tests/regressiontests/forms/tests.py
@@ -2682,6 +2682,47 @@
2682 2682
 <li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li>
2683 2683
 <li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li>
2684 2684
 
  2685
+# Subclassing forms ###########################################################
  2686
+
  2687
+You can subclass a Form to add fields. The resulting form subclass will have
  2688
+all of the fields of the parent Form, plus whichever fields you define in the
  2689
+subclass.
  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
+
  2708
+Yes, you can subclass multiple forms. The fields are added in the order in
  2709
+which 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
+
2685 2726
 # Forms with prefixes #########################################################
2686 2727
 
2687 2728
 Sometimes it's necessary to have multiple forms display on the same HTML page,

0 notes on commit 0518205

Please sign in to comment.
Something went wrong with that request. Please try again.