mirror of
				https://github.com/django/django.git
				synced 2025-11-04 01:47:52 +03:00 
			
		
		
		
	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
	
	Block a user