Django

Code

Changeset 6844

Show
Ignore:
Timestamp:
12/02/07 13:29:54 (7 months ago)
Author:
mtredinnick
Message:

Fixed #6042 -- ModelForms? implementation from Joseph Kocherhans. Still might
need a little tweaking as people start to use it, but this is mostly complete.

Files:

Legend:

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

    r6699 r6844  
    77from django.utils.encoding import smart_unicode 
    88from django.utils.datastructures import SortedDict 
    9  
    10 from util import ValidationError 
     9from django.core.exceptions import ImproperlyConfigured 
     10 
     11from util import ValidationError, ErrorList 
    1112from forms import BaseForm 
    1213from fields import Field, ChoiceField, EMPTY_VALUES 
     
    1415 
    1516__all__ = ( 
     17    'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model', 
    1618    'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields', 
    1719    'ModelChoiceField', 'ModelMultipleChoiceField' 
     
    133135    return type('FormForFields', (BaseForm,), {'base_fields': fields}) 
    134136 
     137 
     138# ModelForms ################################################################# 
     139 
     140def model_to_dict(instance, fields=None, exclude=None): 
     141    """ 
     142    Returns a dict containing the data in ``instance`` suitable for passing as 
     143    a Form's ``initial`` keyword argument. 
     144     
     145    ``fields`` is an optional list of field names. If provided, only the named 
     146    fields will be included in the returned dict. 
     147     
     148    ``exclude`` is an optional list of field names. If provided, the named 
     149    fields will be excluded from the returned dict, even if they are listed in 
     150    the ``fields`` argument. 
     151    """ 
     152    # avoid a circular import 
     153    from django.db.models.fields.related import ManyToManyField 
     154    opts = instance._meta 
     155    data = {} 
     156    for f in opts.fields + opts.many_to_many: 
     157        if not f.editable: 
     158            continue 
     159        if fields and not f.name in fields: 
     160            continue 
     161        if exclude and f.name in exclude: 
     162            continue 
     163        if isinstance(f, ManyToManyField): 
     164            # If the object doesn't have a primry key yet, just use an empty 
     165            # list for its m2m fields. Calling f.value_from_object will raise 
     166            # an exception. 
     167            if instance.pk is None: 
     168                data[f.name] = [] 
     169            else: 
     170                # MultipleChoiceWidget needs a list of pks, not object instances. 
     171                data[f.name] = [obj.pk for obj in f.value_from_object(instance)] 
     172        else: 
     173            data[f.name] = f.value_from_object(instance) 
     174    return data 
     175 
     176def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()): 
     177    """ 
     178    Returns a ``SortedDict`` containing form fields for the given model. 
     179 
     180    ``fields`` is an optional list of field names. If provided, only the named 
     181    fields will be included in the returned fields. 
     182     
     183    ``exclude`` is an optional list of field names. If provided, the named 
     184    fields will be excluded from the returned fields, even if they are listed 
     185    in the ``fields`` argument. 
     186    """ 
     187    # TODO: if fields is provided, it would be nice to return fields in that order 
     188    field_list = [] 
     189    opts = model._meta 
     190    for f in opts.fields + opts.many_to_many: 
     191        if not f.editable: 
     192            continue 
     193        if fields and not f.name in fields: 
     194            continue 
     195        if exclude and f.name in exclude: 
     196            continue 
     197        formfield = formfield_callback(f) 
     198        if formfield: 
     199            field_list.append((f.name, formfield)) 
     200    return SortedDict(field_list) 
     201 
     202class ModelFormOptions(object): 
     203    def __init__(self, options=None): 
     204        self.model = getattr(options, 'model', None) 
     205        self.fields = getattr(options, 'fields', None) 
     206        self.exclude = getattr(options, 'exclude', None) 
     207 
     208class ModelFormMetaclass(type): 
     209    def __new__(cls, name, bases, attrs): 
     210        # TODO: no way to specify formfield_callback yet, do we need one, or 
     211        # should it be a special case for the admin? 
     212        fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] 
     213        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter)) 
     214 
     215        # If this class is subclassing another Form, add that Form's fields. 
     216        # Note that we loop over the bases in *reverse*. This is necessary in 
     217        # order to preserve the correct order of fields. 
     218        for base in bases[::-1]: 
     219            if hasattr(base, 'base_fields'): 
     220                fields = base.base_fields.items() + fields 
     221        declared_fields = SortedDict(fields) 
     222 
     223        opts = ModelFormOptions(attrs.get('Meta', None)) 
     224        attrs['_meta'] = opts 
     225 
     226        # Don't allow more than one Meta model defenition in bases. The fields 
     227        # would be generated correctly, but the save method won't deal with 
     228        # more than one object. 
     229        base_models = [] 
     230        for base in bases: 
     231            base_opts = getattr(base, '_meta', None) 
     232            base_model = getattr(base_opts, 'model', None) 
     233            if base_model is not None: 
     234                base_models.append(base_model) 
     235        if len(base_models) > 1: 
     236            raise ImproperlyConfigured("%s's base classes define more than one model." % name) 
     237 
     238        # If a model is defined, extract form fields from it and add them to base_fields 
     239        if attrs['_meta'].model is not None: 
     240            # Don't allow a subclass to define a Meta model if a parent class has. 
     241            # Technically the right fields would be generated, but the save  
     242            # method will not deal with more than one model. 
     243            for base in bases: 
     244                base_opts = getattr(base, '_meta', None) 
     245                base_model = getattr(base_opts, 'model', None) 
     246                if base_model is not None: 
     247                    raise ImproperlyConfigured('%s defines more than one model.' % name) 
     248            model_fields = fields_for_model(opts.model, opts.fields, opts.exclude) 
     249            # fields declared in base classes override fields from the model 
     250            model_fields.update(declared_fields) 
     251            attrs['base_fields'] = model_fields 
     252        else: 
     253            attrs['base_fields'] = declared_fields 
     254        return type.__new__(cls, name, bases, attrs) 
     255 
     256class BaseModelForm(BaseForm): 
     257    def __init__(self, instance, data=None, files=None, auto_id='id_%s', prefix=None, 
     258                 initial=None, error_class=ErrorList, label_suffix=':'): 
     259        self.instance = instance 
     260        opts = self._meta 
     261        object_data = model_to_dict(instance, opts.fields, opts.exclude) 
     262        # if initial was provided, it should override the values from instance 
     263        if initial is not None: 
     264            object_data.update(initial) 
     265        BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix) 
     266 
     267    def save(self, commit=True): 
     268        """ 
     269        Saves this ``form``'s cleaned_data into model instance ``self.instance``. 
     270 
     271        If commit=True, then the changes to ``instance`` will be saved to the 
     272        database. Returns ``instance``. 
     273        """ 
     274        if self.instance.pk is None: 
     275            fail_message = 'created' 
     276        else: 
     277            fail_message = 'changed' 
     278        return save_instance(self, self.instance, self._meta.fields, fail_message, commit) 
     279 
     280class ModelForm(BaseModelForm): 
     281    __metaclass__ = ModelFormMetaclass 
     282 
     283 
     284# Fields ##################################################################### 
     285 
    135286class QuerySetIterator(object): 
    136287    def __init__(self, queryset, empty_label, cache_choices): 
     
    143294            yield (u"", self.empty_label) 
    144295        for obj in self.queryset: 
    145             yield (obj._get_pk_val(), smart_unicode(obj)) 
     296            yield (obj.pk, smart_unicode(obj)) 
    146297        # Clear the QuerySet cache if required. 
    147298        if not self.cache_choices: 
  • django/trunk/docs/newforms.txt

    r6803 r6844  
    17711771=========================== 
    17721772 
    1773 If you're building a database-driven app, chances are you'll have forms that 
    1774 map closely to Django models. For instance, you might have a ``BlogComment`` 
    1775 model, and you want to create a form that lets people submit comments. In this 
    1776 case, it would be redundant to define the field types in your form, because 
    1777 you've already defined the fields in your model. 
    1778  
    1779 For this reason, Django provides a few helper functions that let you create a 
    1780 ``Form`` class from a Django model. 
    1781  
    1782 ``form_for_model()`` 
    1783 -------------------- 
    1784  
    1785 The method ``django.newforms.form_for_model()`` creates a form based on the 
    1786 definition of a specific model. Pass it the model class, and it will return a 
    1787 ``Form`` class that contains a form field for each model field. 
    1788  
    1789 For example:: 
    1790  
    1791     >>> from django.newforms import form_for_model 
    1792  
    1793     # Create the form class. 
    1794     >>> ArticleForm = form_for_model(Article) 
    1795  
    1796     # Create an empty form instance. 
    1797     >>> f = ArticleForm() 
    1798  
    1799 It bears repeating that ``form_for_model()`` takes the model *class*, not a 
    1800 model instance, and it returns a ``Form`` *class*, not a ``Form`` instance. 
    1801  
    1802 Field types 
    1803 ~~~~~~~~~~~ 
    1804  
    1805 The generated ``Form`` class will have a form field for every model field. Each 
    1806 model field has a corresponding default form field. For example, a 
    1807 ``CharField`` on a model is represented as a ``CharField`` on a form. A 
    1808 model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is 
    1809 the full list of conversions: 
    1810  
    1811     ===============================  ======================================== 
    1812     Model field                      Form field 
    1813     ===============================  ======================================== 
    1814     ``AutoField``                    Not represented in the form 
    1815     ``BooleanField``                 ``BooleanField`` 
    1816     ``CharField``                    ``CharField`` with ``max_length`` set to 
    1817                                      the model field's ``max_length`` 
    1818     ``CommaSeparatedIntegerField``   ``CharField`` 
    1819     ``DateField``                    ``DateField`` 
    1820     ``DateTimeField``                ``DateTimeField`` 
    1821     ``DecimalField``                 ``DecimalField`` 
    1822     ``EmailField``                   ``EmailField`` 
    1823     ``FileField``                    ``FileField`` 
    1824     ``FilePathField``                ``CharField`` 
    1825     ``FloatField``                   ``FloatField`` 
    1826     ``ForeignKey``                   ``ModelChoiceField`` (see below) 
    1827     ``ImageField``                   ``ImageField`` 
    1828     ``IntegerField``                 ``IntegerField`` 
    1829     ``IPAddressField``               ``IPAddressField`` 
    1830     ``ManyToManyField``              ``ModelMultipleChoiceField`` (see 
    1831                                      below) 
    1832     ``NullBooleanField``             ``CharField`` 
    1833     ``PhoneNumberField``             ``USPhoneNumberField`` 
    1834                                      (from ``django.contrib.localflavor.us``) 
    1835     ``PositiveIntegerField``         ``IntegerField`` 
    1836     ``PositiveSmallIntegerField``    ``IntegerField`` 
    1837     ``SlugField``                    ``CharField`` 
    1838     ``SmallIntegerField``            ``IntegerField`` 
    1839     ``TextField``                    ``CharField`` with ``widget=Textarea`` 
    1840     ``TimeField``                    ``TimeField`` 
    1841     ``URLField``                     ``URLField`` with ``verify_exists`` set 
    1842                                      to the model field's ``verify_exists`` 
    1843     ``USStateField``                 ``CharField`` with 
    1844                                      ``widget=USStateSelect`` 
    1845                                      (``USStateSelect`` is from 
    1846                                      ``django.contrib.localflavor.us``) 
    1847     ``XMLField``                     ``CharField`` with ``widget=Textarea`` 
    1848     ===============================  ======================================== 
    1849  
    1850  
    1851 .. note:: 
    1852     The ``FloatField`` form field and ``DecimalField`` model and form fields 
    1853     are new in the development version. 
    1854  
    1855 As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field 
    1856 types are special cases: 
    1857  
    1858     * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``, 
    1859       which is a ``ChoiceField`` whose choices are a model ``QuerySet``. 
    1860  
    1861     * ``ManyToManyField`` is represented by 
    1862       ``django.newforms.ModelMultipleChoiceField``, which is a 
    1863       ``MultipleChoiceField`` whose choices are a model ``QuerySet``. 
    1864  
    1865 In addition, each generated form field has attributes set as follows: 
    1866  
    1867     * If the model field has ``blank=True``, then ``required`` is set to 
    1868       ``False`` on the form field. Otherwise, ``required=True``. 
    1869  
    1870     * The form field's ``label`` is set to the ``verbose_name`` of the model 
    1871       field, with the first character capitalized. 
    1872  
    1873     * The form field's ``help_text`` is set to the ``help_text`` of the model 
    1874       field. 
    1875  
    1876     * If the model field has ``choices`` set, then the form field's ``widget`` 
    1877       will be set to ``Select``, with choices coming from the model field's 
    1878       ``choices``. 
    1879  
    1880       The choices will include the "blank" choice, which is selected by 
    1881       default. If the field is required, this forces the user to make a 
    1882       selection. The blank choice will not be included if the model 
    1883       field has ``blank=False`` and an explicit ``default`` value, in which 
    1884       case the ``default`` value will be initially selected instead. 
    1885  
    1886 Finally, note that you can override the form field used for a given model 
    1887 field. See "Overriding the default field types" below. 
    1888  
    1889 A full example 
    1890 ~~~~~~~~~~~~~~ 
    1891  
    1892 Consider this set of models:: 
    1893  
    1894     from django.db import models 
    1895  
    1896     TITLE_CHOICES = ( 
    1897         ('MR', 'Mr.'), 
    1898         ('MRS', 'Mrs.'), 
    1899         ('MS', 'Ms.'), 
    1900     ) 
    1901  
    1902     class Author(models.Model): 
    1903         name = models.CharField(max_length=100) 
    1904         title = models.CharField(max_length=3, choices=TITLE_CHOICES) 
    1905         birth_date = models.DateField(blank=True, null=True) 
    1906  
    1907         def __unicode__(self): 
    1908             return self.name 
    1909  
    1910     class Book(models.Model): 
    1911         name = models.CharField(max_length=100) 
    1912         authors = models.ManyToManyField(Author) 
    1913  
    1914 With these models, a call to ``form_for_model(Author)`` would return a ``Form`` 
    1915 class equivalent to this:: 
    1916  
    1917     class AuthorForm(forms.Form): 
    1918         name = forms.CharField(max_length=100) 
    1919         title = forms.CharField(max_length=3, 
    1920                     widget=forms.Select(choices=TITLE_CHOICES)) 
    1921         birth_date = forms.DateField(required=False) 
    1922  
    1923 A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to 
    1924 this:: 
    1925  
    1926     class BookForm(forms.Form): 
    1927         name = forms.CharField(max_length=100) 
    1928         authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) 
    1929  
    1930 The ``save()`` method 
    1931 ~~~~~~~~~~~~~~~~~~~~~ 
    1932  
    1933 Every form produced by ``form_for_model()`` also has a ``save()`` method. This 
    1934 method creates and saves a database object from the data bound to the form. For 
    1935 example:: 
    1936  
    1937     # Create a form instance from POST data. 
    1938     >>> f = ArticleForm(request.POST) 
    1939  
    1940     # Save a new Article object from the form's data. 
    1941     >>> new_article = f.save() 
    1942  
    1943 Note that ``save()`` will raise a ``ValueError`` if the data in the form 
    1944 doesn't validate -- i.e., ``if form.errors``. 
    1945  
    1946 This ``save()`` method accepts an optional ``commit`` keyword argument, which 
    1947 accepts either ``True`` or ``False``. If you call ``save()`` with 
    1948 ``commit=False``, then it will return an object that hasn't yet been saved to 
    1949 the database. In this case, it's up to you to call ``save()`` on the resulting 
    1950 model instance. This is useful if you want to do custom processing on the 
    1951 object before saving it. ``commit`` is ``True`` by default. 
    1952  
    1953 Another side effect of using ``commit=False`` is seen when your model has 
    1954 a many-to-many relation with another model. If your model has a many-to-many 
    1955 relation and you specify ``commit=False`` when you save a form, Django cannot 
    1956 immediately save the form data for the many-to-many relation. This is because 
    1957 it isn't possible to save many-to-many data for an instance until the instance 
    1958 exists in the database. 
    1959  
    1960 To work around this problem, every time you save a form using ``commit=False``, 
    1961 Django adds a ``save_m2m()`` method to the form created by ``form_for_model``. 
    1962 After you've manually saved the instance produced by the form, you can invoke 
    1963 ``save_m2m()`` to save the many-to-many form data. For example:: 
    1964  
    1965     # Create a form instance with POST data. 
    1966     >>> f = AuthorForm(request.POST) 
    1967  
    1968     # Create, but don't save the new author instance. 
    1969     >>> new_author = f.save(commit=False) 
    1970  
    1971     # Modify the author in some way. 
    1972     >>> new_author.some_field = 'some_value' 
    1973  
    1974     # Save the new instance. 
    1975     >>> new_author.save() 
    1976  
    1977     # Now, save the many-to-many data for the form. 
    1978     >>> f.save_m2m() 
    1979  
    1980 Calling ``save_m2m()`` is only required if you use ``save(commit=False)``. 
    1981 When you use a simple ``save()`` on a form, all data -- including 
    1982 many-to-many data -- is saved without the need for any additional method calls. 
    1983 For example:: 
    1984  
    1985     # Create a form instance with POST data. 
    1986     >>> f = AuthorForm(request.POST) 
    1987  
    1988     # Create and save the new author instance. There's no need to do anything else. 
    1989     >>> new_author = f.save() 
    1990  
    1991 Using an alternate base class 
    1992 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    1993  
    1994 If you want to add custom methods to the form generated by 
    1995 ``form_for_model()``, write a class that extends ``django.newforms.BaseForm`` 
    1996 and contains your custom methods. Then, use the ``form`` argument to 
    1997 ``form_for_model()`` to tell it to use your custom form as its base class. 
    1998 For example:: 
    1999  
    2000     # Create the new base class. 
    2001     >>> class MyBase(BaseForm): 
    2002     ...     def my_method(self): 
    2003     ...         # Do whatever the method does 
    2004  
    2005     # Create the form class with a different base class. 
    2006     >>> ArticleForm = form_for_model(Article, form=MyBase) 
    2007  
    2008     # Instantiate the form. 
    2009     >>> f = ArticleForm() 
    2010  
    2011     # Use the base class method. 
    2012     >>> f.my_method() 
    2013  
    2014 Using a subset of fields on the form 
    2015 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2016  
    2017 **New in Django development version** 
    2018  
    2019 In some cases, you may not want all the model fields to appear on the generated 
    2020 form. There are two ways of telling ``form_for_model()`` to use only a subset 
    2021 of the model fields: 
    2022  
    2023     1. Set ``editable=False`` on the model field. As a result, *any* form 
    2024        created from the model via ``form_for_model()`` will not include that 
    2025        field. 
    2026  
    2027     2. Use the ``fields`` argument to ``form_for_model()``. This argument, if 
    2028        given, should be a list of field names to include in the form. 
    2029  
    2030        For example, if you want a form for the ``Author`` model (defined above) 
    2031        that includes only the ``name`` and ``title`` fields, you would specify 
    2032        ``fields`` like this:: 
    2033  
    2034            PartialArticleForm = form_for_model(Author, fields=('name', 'title')) 
    2035  
    2036 .. note:: 
    2037  
    2038     If you specify ``fields`` when creating a form with ``form_for_model()``, 
    2039     then the fields that are *not* specified will not be set by the form's 
    2040     ``save()`` method. Django will prevent any attempt to save an incomplete 
    2041     model, so if the model does not allow the missing fields to be empty, and 
    2042     does not provide a default value for the missing fields, any attempt to 
    2043     ``save()`` a ``form_for_model`` with missing fields will fail. To avoid 
    2044     this failure, you must use ``save(commit=False)`` and manually set any 
    2045     extra required fields:: 
    2046  
    2047         instance = form.save(commit=False) 
    2048         instance.required_field = 'new value' 
    2049         instance.save() 
    2050  
    2051     See the `section on saving forms`_ for more details on using 
    2052     ``save(commit=False)``. 
    2053  
    2054 .. _section on saving forms: `The save() method`_ 
    2055  
    2056 Overriding the default field types 
    2057 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2058  
    2059 The default field types, as described in the "Field types" table above, are 
    2060 sensible defaults; if you have a ``DateField`` in your model, chances are you'd 
    2061 want that to be represented as a ``DateField`` in your form. But 
    2062 ``form_for_model()`` gives you the flexibility of changing the form field type 
    2063 for a given model field. You do this by specifying a **formfield callback**. 
    2064  
    2065 A formfield callback is a function that, when provided with a model field, 
    2066 returns a form field instance. When constructing a form, ``form_for_model()`` 
    2067 asks the formfield callback to provide form field types. 
    2068  
    2069 By default, ``form_for_model()`` calls the ``formfield()`` method on the model 
    2070 field:: 
    2071  
    2072     def default_callback(field, **kwargs): 
    2073         return field.formfield(**kwargs) 
    2074  
    2075 The ``kwargs`` are any keyword arguments that might be passed to the form 
    2076 field, such as ``required=True`` or ``label='Foo'``. 
    2077  
    2078 For example, if you wanted to use ``MyDateFormField`` for any ``DateField`` 
    2079 field on the model, you could define the callback:: 
    2080  
    2081     >>> def my_callback(field, **kwargs): 
    2082     ...     if isinstance(field, models.DateField): 
    2083     ...         return MyDateFormField(**kwargs) 
    2084     ...     else: 
    2085     ...         return field.formfield(**kwargs) 
    2086  
    2087     >>> ArticleForm = form_for_model(Article, formfield_callback=my_callback) 
    2088  
    2089 Note that your callback needs to handle *all* possible model field types, not 
    2090 just the ones that you want to behave differently to the default. That's why 
    2091 this example has an ``else`` clause that implements the default behavior. 
    2092  
    2093 .. warning:: 
    2094     The field that is passed into the ``formfield_callback`` function in 
    2095     ``form_for_model()`` and ``form_for_instance`` is the field instance from 
    2096     your model's class. You **must not** alter that object at all; treat it 
    2097     as read-only! 
    2098  
    2099     If you make any alterations to that object, it will affect any future 
    2100     users of the model class, because you will have changed the field object 
    2101     used to construct the class. This is almost certainly what you don't want 
    2102     to have happen. 
    2103  
    2104 Finding the model associated with a form 
    2105 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2106  
    2107 The model class that was used to construct the form is available 
    2108 using the ``_model`` property of the generated form:: 
    2109  
    2110     >>> ArticleForm = form_for_model(Article) 
    2111     >>> ArticleForm._model 
    2112     <class 'myapp.models.Article'> 
    2113  
    2114 ``form_for_instance()`` 
    2115 ----------------------- 
    2116  
    2117 ``form_for_instance()`` is like ``form_for_model()``, but it takes a model 
    2118 instance instead of a model class:: 
    2119  
    2120     # Create an Author. 
    2121     >>> a = Author(name='Joe Smith', title='MR', birth_date=None) 
    2122     >>> a.save() 
    2123  
    2124     # Create a form for this particular Author. 
    2125     >>> AuthorForm = form_for_instance(a) 
    2126  
    2127     # Instantiate the form. 
    2128     >>> f = AuthorForm() 
    2129  
    2130 When a form created by ``form_for_instance()`` is created, the initial data 
    2131 values for the form fields are drawn from the instance. However, this data is 
    2132 not bound to the form. You will need to bind data to the form before the form 
    2133 can be saved. 
    2134  
    2135 Unlike ``form_for_model()``, a choice field in form created by 
    2136 ``form_for_instance()`` will not include the blank choice if the respective 
    2137 model field has ``blank=False``. The initial choice is drawn from the instance. 
    2138  
    2139 When you call ``save()`` on a form created by ``form_for_instance()``, 
    2140 the database instance will be updated. As in ``form_for_model()``, ``save()`` 
    2141 will raise ``ValueError`` if the data doesn't validate. 
    2142  
    2143 ``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback`` 
    2144 arguments that behave the same way as they do for ``form_for_model()``. 
    2145  
    2146 Let's modify the earlier `contact form`_ view example a little bit. Suppose we 
    2147 have a ``Message`` model that holds each contact submission. Something like:: 
    2148  
    2149     class Message(models.Model): 
    2150         subject = models.CharField(max_length=100) 
    2151         message = models.TextField() 
    2152         sender = models.EmailField() 
    2153         cc_myself = models.BooleanField(required=False) 
    2154  
    2155 You could use this model to create a form (using ``form_for_model()``). You 
    2156 could also use existing ``Message`` instances to create a form for editing 
    2157 messages. The earlier_ view can be changed slightly to accept the ``id`` value 
    2158 of an existing ``Message`` and present it for editing:: 
    2159  
    2160     def contact_edit(request, msg_id): 
    2161         # Create the form from the message id. 
    2162         message = get_object_or_404(Message, id=msg_id) 
    2163         ContactForm = form_for_instance(message) 
    2164  
    2165         if request.method == 'POST': 
    2166             form = ContactForm(request.POST) 
    2167             if form.is_valid(): 
    2168                 form.save() 
    2169                 return HttpResponseRedirect('/url/on_success/') 
    2170         else: 
    2171             form = ContactForm() 
    2172         return render_to_response('contact.html', {'form': form}) 
    2173  
    2174 Aside from how we create the ``ContactForm`` class here, the main point to 
    2175 note is that the form display in the ``GET`` branch of the function 
    2176 will use the values from the ``message`` instance as initial values for the 
    2177 form field. 
    2178  
    2179 .. _contact form: `Simple view example`_ 
    2180 .. _earlier: `Simple view example`_ 
    2181  
    2182 When should you use ``form_for_model()`` and ``form_for_instance()``? 
    2183 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2184  
    2185 The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be 
    2186 shortcuts for the common case. If you want to create a form whose fields map to 
    2187 more than one model, or a form that contains fields that *aren't* on a model, 
    2188 you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way 
    2189 isn't that difficult, after all. 
     1773The prefered way of generating forms that work with models is explained in the 
     1774`ModelForms documentation`_. 
     1775 
     1776Looking for the ``form_for_model`` and ``form_for_instance`` documentation? 
     1777They've been deprecated, but you can still `view the documentation`_. 
     1778 
     1779.. _ModelForms documentation: ../modelforms/ 
     1780.. _view the documentation: ../form_for_model/ 
    21901781 
    21911782More coming soon 
  • django/trunk/tests/modeltests/model_forms/models.py

    r6733 r6844  
    11""" 
    2 36. Generating HTML forms from models 
    3  
    4 Django provides shortcuts for creating Form objects from a model class and a 
    5 model instance. 
    6  
    7 The function django.newforms.form_for_model() takes a model class and returns 
    8 a Form that is tied to the model. This Form works just like any other Form, 
    9 with one additional method: save(). The save() method creates an instance 
    10 of the model and returns that newly created instance. It saves the instance to 
    11 the database if save(commit=True), which is default. If you pass 
    12 commit=False, then you'll get the object without committing the changes to the 
    13 database. 
    14  
    15 The function django.newforms.form_for_instance() takes a model instance and 
    16 returns a Form that is tied to the instance. This form works just like any 
    17 other Form, with one additional method: save(). The save() 
    18 method updates the model instance. It also takes a commit=True parameter. 
    19  
    20 The function django.newforms.save_instance() takes a bound form instance and a 
    21 model instance and saves the form's cleaned_data into the instance. It also takes 
    22 a commit=True parameter. 
     2XX. Generating HTML forms from models 
     3 
     4This is mostly just a reworking of the form_for_model/form_for_instance tests 
     5to use ModelForm. As such, the text may not make sense in all cases, and the 
     6examples are probably a poor fit for the ModelForm syntax. In other words, 
     7most of these tests should be rewritten. 
    238""" 
    249 
     
    2914    (2, 'Pending'), 
    3015    (3, 'Live'), 
    31 ) 
    32  
    33 STEERING_TYPE = ( 
    34     ('left', 'Left steering wheel'), 
    35     ('right', 'Right steering wheel'), 
    36 ) 
    37  
    38 FUEL_TYPE = ( 
    39     ('gas', 'Gasoline'), 
    40     ('diesel', 'Diesel'), 
    41     ('other', 'Other'), 
    42 ) 
    43  
    44 TRANSMISSION_TYPE = ( 
    45     ('at', 'Automatic'), 
    46     ('mt', 'Manual'), 
    47     ('cvt', 'CVT'), 
    4816) 
    4917 
     
    8856        return self.phone 
    8957 
    90 class Car(models.Model): 
    91     name = models.CharField(max_length=50) 
    92     steering = models.CharField(max_length=5, choices=STEERING_TYPE, default='left') 
    93     fuel = models.CharField(max_length=10, choices=FUEL_TYPE) 
    94     transmission = models.CharField(max_length=3, choices=TRANSMISSION_TYPE, blank=True, help_text='Leave empty if not applicable.') 
    95  
    9658__test__ = {'API_TESTS': """ 
    97 >>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField 
     59>>> from django import newforms as forms 
     60>>> from django.newforms.models import ModelForm 
     61 
     62The bare bones, absolutely nothing custom, basic case. 
     63 
     64>>> class CategoryForm(ModelForm): 
     65...     class Meta: 
     66...         model = Category 
     67>>> CategoryForm.base_fields.keys() 
     68['name', 'slug', 'url'] 
     69 
     70 
     71Extra fields. 
     72 
     73>>> class CategoryForm(ModelForm): 
     74...     some_extra_field = forms.BooleanField() 
     75... 
     76...     class Meta: 
     77...         model = Category 
     78 
     79>>> CategoryForm.base_fields.keys() 
     80['name', 'slug', 'url', 'some_extra_field'] 
     81 
     82 
     83Replacing a field. 
     84 
     85>>> class CategoryForm(ModelForm): 
     86...     url = forms.BooleanField() 
     87... 
     88...     class Meta: 
     89...         model = Category 
     90 
     91>>> CategoryForm.base_fields['url'].__class__ 
     92<class 'django.newforms.fields.BooleanField'> 
     93 
     94 
     95Using 'fields'. 
     96 
     97>>> class CategoryForm(ModelForm): 
     98... 
     99...     class Meta: 
     100...         model = Category 
     101...         fields = ['url'] 
     102 
     103>>> CategoryForm.base_fields.keys() 
     104['url'] 
     105 
     106 
     107Using 'exclude' 
     108 
     109>>> class CategoryForm(ModelForm): 
     110... 
     111...     class Meta: 
     112...         model = Category 
     113...         exclude = ['url'] 
     114 
     115>>> CategoryForm.base_fields.keys() 
     116['name', 'slug'] 
     117 
     118 
     119Using 'fields' *and* 'exclude'. Not sure why you'd want to do this, but uh, 
     120"be liberal in what you accept" and all. 
     121 
     122>>> class CategoryForm(ModelForm): 
     123... 
     124...     class Meta: 
     125...         model = Category 
     126...         fields = ['name', 'url'] 
     127...         exclude = ['url'] 
     128 
     129>>> CategoryForm.base_fields.keys() 
     130['name'] 
     131 
     132Don't allow more than one 'model' definition in the inheritance hierarchy. 
     133Technically, it would generate a valid form, but the fact that the resulting 
     134save method won't deal with multiple objects is likely to trip up people not 
     135familiar with the mechanics. 
     136 
     137>>> class CategoryForm(ModelForm): 
     138...     class Meta: 
     139...         model = Category 
     140 
     141>>> class BadForm(CategoryForm): 
     142...     class Meta: 
     143...         model = Article 
     144Traceback (most recent call last): 
     145... 
     146ImproperlyConfigured: BadForm defines more than one model. 
     147 
     148>>> class ArticleForm(ModelForm): 
     149...     class Meta: 
     150...         model = Article 
     151 
     152>>> class BadForm(ArticleForm, CategoryForm): 
     153...     pass 
     154Traceback (most recent call last): 
     155... 
     156ImproperlyConfigured: BadForm's base classes define more than one model. 
     157 
     158 
     159# Old form_for_x tests ####################################################### 
     160 
     161>>> from django.newforms import ModelForm, CharField 
    98162>>> import datetime 
    99163 
     
    101165[] 
    102166 
    103 >>> CategoryForm = form_for_model(Category) 
    104 >>> f = CategoryForm() 
     167>>> class CategoryForm(ModelForm): 
     168...     class Meta: 
     169...         model = Category 
     170>>> f = CategoryForm(Category()) 
    105171>>> print f 
    106172<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr> 
     
    114180<input id="id_name" type="text" name="name" maxlength="20" /> 
    115181 
    116 >>> f = CategoryForm(auto_id=False) 
     182>>> f = CategoryForm(Category(), auto_id=False) 
    117183>>> print f.as_ul() 
    118184<li>Name: <input type="text" name="name" maxlength="20" /></li> 
     
    120186<li>The URL: <input type="text" name="url" maxlength="40" /></li> 
    121187 
    122 >>> f = CategoryForm({'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'}) 
     188>>> f = CategoryForm(Category(), {'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'}) 
    123189>>> f.is_valid() 
    124190True 
     
    131197[<Category: Entertainment>] 
    132198 
    133 >>> f = CategoryForm({'name': "It's a test", 'slug': 'its-test', 'url': 'test'}) 
     199>>> f = CategoryForm(Category(), {'name': "It's a test", 'slug': 'its-test', 'url': 'test'}) 
    134200>>> f.is_valid() 
    135201True 
     
    145211hasn't yet been saved to the database. In this case, it's up to you to call 
    146212save() on the resulting model instance. 
    147 >>> f = CategoryForm({'name': 'Third test', 'slug': 'third-test', 'url': 'third'}) 
     213>>> f = CategoryForm(Category(), {'name': 'Third test', 'slug': 'third-test', 'url': 'third'}) 
    148214>>> f.is_valid() 
    149215True 
     
    160226 
    161227If you call save() with invalid data, you'll get a ValueError. 
    162 >>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'}) 
     228>>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'}) 
    163229>>> f.errors 
    164230{'name': [u'This field is required.'], 'slug': [u'This field is required.']} 
     
    171237... 
    172238ValueError: The Category could not be created because the data didn't validate. 
    173 >>> f = CategoryForm({'name': '', 'slug': '', 'url': 'foo'}) 
     239>>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'}) 
    174240>>> f.save() 
    175241Traceback (most recent call last): 
     
    185251ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any 
    186252fields with the 'choices' attribute are represented by a ChoiceField. 
    187 >>> ArticleForm = form_for_model(Article) 
    188 >>> f = ArticleForm(auto_id=False) 
     253>>> class ArticleForm(ModelForm): 
     254...     class Meta: 
     255...         model = Article 
     256>>> f = ArticleForm(Article(), auto_id=False) 
    189257>>> print f 
    190258<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> 
     
    215283a value of None. If a field isn't specified on a form, the object created 
    216284from the form can't provide a value for that field! 
    217 >>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date')) 
    218 >>> f = PartialArticleForm(auto_id=False) 
     285>>> class PartialArticleForm(ModelForm): 
     286...     class Meta: 
     287...         model = Article 
     288...         fields = ('headline','pub_date') 
     289>>> f = PartialArticleForm(Article(), auto_id=False) 
    219290>>> print f 
    220291<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> 
    221292<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> 
    222  
    223 You can pass a custom Form class to form_for_model. Make sure it's a 
    224 subclass of BaseForm, not Form. 
    225 >>> class CustomForm(BaseForm): 
    226 ...     def say_hello(self): 
    227 ...         print 'hello' 
    228 >>> CategoryForm = form_for_model(Category, form=CustomForm) 
    229 >>> f = CategoryForm() 
    230 >>> f.say_hello() 
    231 hello 
    232293 
    233294Use form_for_instance to create a Form from a model instance. The difference 
     
    235296current values are inserted as 'initial' data in each Field. 
    236297>>> w = Writer.objects.get(name='Mike Royko') 
    237 >>> RoykoForm = form_for_instance(w) 
    238 >>> f = RoykoForm(auto_id=False) 
     298>>> class RoykoForm(ModelForm): 
     299...     class Meta: 
     300...         model = Writer 
     301>>> f = RoykoForm(w, auto_id=False) 
    239302>>> print f 
    240303<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr> 
     
    244307>>> art.id 
    2453081 
    246 >>> TestArticleForm = form_for_instance(art) 
    247 >>> f = TestArticleForm(auto_id=False) 
     309>>> class TestArticleForm(ModelForm): 
     310...     class Meta: 
     311...         model = Article 
     312>>> f = TestArticleForm(art, auto_id=False) 
    248313>>> print f.as_ul() 
    249314<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li> 
     
    267332<option value="3">Third test</option> 
    268333</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li> 
    269 >>> f = TestArticleForm({'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) 
     334>>> f = TestArticleForm(art, {'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) 
    270335>>> f.is_valid() 
    271336True 
     
    279344You can create a form over a subset of the available fields 
    280345by specifying a 'fields' argument to form_for_instance. 
    281 >>> PartialArticleForm = form_for_instance(art, fields=('headline', 'slug', 'pub_date')) 
    282 >>> f = PartialArticleForm({'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False) 
     346>>> class PartialArticleForm(ModelForm): 
     347...     class Meta: 
     348...         model = Article 
     349...         fields=('headline', 'slug', 'pub_date') 
     350>>> f = PartialArticleForm(art, {'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False) 
    283351>>> print f.as_ul() 
    284352<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> 
     
    300368>>> new_art.categories.all() 
    301369[<Category: Entertainment>] 
    302 >>> TestArticleForm = form_for_instance(new_art) 
    303 >>> f = TestArticleForm(auto_id=False) 
     370>>> class TestArticleForm(ModelForm): 
     371...     class Meta: 
     372...         model = Article 
     373>>> f = TestArticleForm(new_art, auto_id=False) 
    304374>>> print f.as_ul() 
    305375<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> 
     
    324394</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li> 
    325395 
    326 >>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04', 
     396>>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04', 
    327397...     'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}) 
    328398>>> new_art = f.save() 
     
    334404 
    335405Now, submit form data with no categories. This deletes the existing categories. 
    336 >>> f = TestArticleForm({'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04', 
     406>>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04', 
    337407...     'writer': u'1', 'article': u'Hello.'}) 
    338408>>> new_art = f.save() 
     
    344414 
    345415Create a new article, with categories, via the form. 
    346 >>> ArticleForm = form_for_model(Article) 
    347 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 
     416>>> class ArticleForm(ModelForm): 
     417...     class Meta: 
     418...         model = Article 
     419>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 
    348420...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 
    349421>>> new_art = f.save() 
     
    355427 
    356428Create a new article, with no categories, via the form. 
    357 >>> ArticleForm = form_for_model(Article) 
    358 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 
     429>>> class ArticleForm(ModelForm): 
     430...     class Meta: 
     431...         model = Article 
     432>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01', 
    359433...     'writer': u'1', 'article': u'Test.'}) 
    360434>>> new_art = f.save() 
     
    367441Create a new article, with categories, via the form, but use commit=False. 
    368442The m2m data won't be saved until save_m2m() is invoked on the form. 
    369 >>> ArticleForm = form_for_model(Article) 
    370 >>> f = ArticleForm({'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01', 
     443>>> class ArticleForm(ModelForm): 
     444...     class Meta: 
     445...         model = Article 
     446>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01', 
    371447...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 
    372448>>> new_art = f.save(commit=False) 
     
    387463[<Category: Entertainment>, <Category: It's a test>] 
    388464 
    389 Here, we define a custom Form. Because it happens to have the same fields as 
    390 the Category model, we can use save_instance() to apply its changes to an 
     465Here, we define a custom ModelForm. Because it happens to have the same fields as 
     466the Category model, we can just call the form's save() to apply its changes to an 
    391467existing Category instance. 
    392 >>> class ShortCategory(Form): 
     468>>> class ShortCategory(ModelForm): 
    393469...     name = CharField(max_length=5) 
    394470...     slug = CharField(max_length=5) 
     
    399475>>> cat.id 
    4004763 
    401 >>> sc = ShortCategory({'name': 'Third', 'slug': 'third', 'url': '3rd'}) 
    402 >>> save_instance(sc, cat
     477>>> form = ShortCategory(cat, {'name': 'Third', 'slug': 'third', 'url': '3rd'}) 
     478>>> form.save(
    403479<Category: Third> 
    404480>>> Category.objects.get(id=3) 
     
    408484at runtime, based on the data in the database when the form is displayed, not 
    409485the data in the database when the form is instantiated. 
    410 >>> ArticleForm = form_for_model(Article) 
    411 >>> f = ArticleForm(auto_id=False) 
     486>>> class ArticleForm(ModelForm): 
     487...     class Meta: 
     488...         model = Article 
     489>>> f = ArticleForm(Article(), auto_id=False) 
    412490