Changeset 6844
- Timestamp:
- 12/02/07 13:29:54 (7 months ago)
- Files:
-
- django/trunk/django/newforms/models.py (modified) (4 diffs)
- django/trunk/docs/form_for_model.txt (added)
- django/trunk/docs/modelforms.txt (added)
- django/trunk/docs/newforms.txt (modified) (1 diff)
- django/trunk/tests/modeltests/model_forms/models.py (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/newforms/models.py
r6699 r6844 7 7 from django.utils.encoding import smart_unicode 8 8 from django.utils.datastructures import SortedDict 9 10 from util import ValidationError 9 from django.core.exceptions import ImproperlyConfigured 10 11 from util import ValidationError, ErrorList 11 12 from forms import BaseForm 12 13 from fields import Field, ChoiceField, EMPTY_VALUES … … 14 15 15 16 __all__ = ( 17 'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model', 16 18 'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields', 17 19 'ModelChoiceField', 'ModelMultipleChoiceField' … … 133 135 return type('FormForFields', (BaseForm,), {'base_fields': fields}) 134 136 137 138 # ModelForms ################################################################# 139 140 def 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 176 def 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 202 class 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 208 class 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 256 class 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 280 class ModelForm(BaseModelForm): 281 __metaclass__ = ModelFormMetaclass 282 283 284 # Fields ##################################################################### 285 135 286 class QuerySetIterator(object): 136 287 def __init__(self, queryset, empty_label, cache_choices): … … 143 294 yield (u"", self.empty_label) 144 295 for obj in self.queryset: 145 yield (obj. _get_pk_val(), smart_unicode(obj))296 yield (obj.pk, smart_unicode(obj)) 146 297 # Clear the QuerySet cache if required. 147 298 if not self.cache_choices: django/trunk/docs/newforms.txt
r6803 r6844 1771 1771 =========================== 1772 1772 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. 1773 The prefered way of generating forms that work with models is explained in the 1774 `ModelForms documentation`_. 1775 1776 Looking for the ``form_for_model`` and ``form_for_instance`` documentation? 1777 They've been deprecated, but you can still `view the documentation`_. 1778 1779 .. _ModelForms documentation: ../modelforms/ 1780 .. _view the documentation: ../form_for_model/ 2190 1781 2191 1782 More coming soon django/trunk/tests/modeltests/model_forms/models.py
r6733 r6844 1 1 """ 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. 2 XX. Generating HTML forms from models 3 4 This is mostly just a reworking of the form_for_model/form_for_instance tests 5 to use ModelForm. As such, the text may not make sense in all cases, and the 6 examples are probably a poor fit for the ModelForm syntax. In other words, 7 most of these tests should be rewritten. 23 8 """ 24 9 … … 29 14 (2, 'Pending'), 30 15 (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'),48 16 ) 49 17 … … 88 56 return self.phone 89 57 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 96 58 __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 62 The 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 71 Extra 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 83 Replacing 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 95 Using '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 107 Using '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 119 Using '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 132 Don't allow more than one 'model' definition in the inheritance hierarchy. 133 Technically, it would generate a valid form, but the fact that the resulting 134 save method won't deal with multiple objects is likely to trip up people not 135 familiar 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 144 Traceback (most recent call last): 145 ... 146 ImproperlyConfigured: 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 154 Traceback (most recent call last): 155 ... 156 ImproperlyConfigured: 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 98 162 >>> import datetime 99 163 … … 101 165 [] 102 166 103 >>> CategoryForm = form_for_model(Category) 104 >>> f = CategoryForm() 167 >>> class CategoryForm(ModelForm): 168 ... class Meta: 169 ... model = Category 170 >>> f = CategoryForm(Category()) 105 171 >>> print f 106 172 <tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr> … … 114 180 <input id="id_name" type="text" name="name" maxlength="20" /> 115 181 116 >>> f = CategoryForm( auto_id=False)182 >>> f = CategoryForm(Category(), auto_id=False) 117 183 >>> print f.as_ul() 118 184 <li>Name: <input type="text" name="name" maxlength="20" /></li> … … 120 186 <li>The URL: <input type="text" name="url" maxlength="40" /></li> 121 187 122 >>> f = CategoryForm( {'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})188 >>> f = CategoryForm(Category(), {'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'}) 123 189 >>> f.is_valid() 124 190 True … … 131 197 [<Category: Entertainment>] 132 198 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'}) 134 200 >>> f.is_valid() 135 201 True … … 145 211 hasn't yet been saved to the database. In this case, it's up to you to call 146 212 save() 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'}) 148 214 >>> f.is_valid() 149 215 True … … 160 226 161 227 If 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'}) 163 229 >>> f.errors 164 230 {'name': [u'This field is required.'], 'slug': [u'This field is required.']} … … 171 237 ... 172 238 ValueError: 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'}) 174 240 >>> f.save() 175 241 Traceback (most recent call last): … … 185 251 ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any 186 252 fields 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) 189 257 >>> print f 190 258 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> … … 215 283 a value of None. If a field isn't specified on a form, the object created 216 284 from 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) 219 290 >>> print f 220 291 <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> 221 292 <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 a224 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 hello232 293 233 294 Use form_for_instance to create a Form from a model instance. The difference … … 235 296 current values are inserted as 'initial' data in each Field. 236 297 >>> 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) 239 302 >>> print f 240 303 <tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr> … … 244 307 >>> art.id 245 308 1 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) 248 313 >>> print f.as_ul() 249 314 <li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li> … … 267 332 <option value="3">Third test</option> 268 333 </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.'}) 270 335 >>> f.is_valid() 271 336 True … … 279 344 You can create a form over a subset of the available fields 280 345 by 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) 283 351 >>> print f.as_ul() 284 352 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> … … 300 368 >>> new_art.categories.all() 301 369 [<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) 304 374 >>> print f.as_ul() 305 375 <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> … … 324 394 </select> Hold down "Control", or "Command" on a Mac, to select more than one.</li> 325 395 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', 327 397 ... 'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']}) 328 398 >>> new_art = f.save() … … 334 404 335 405 Now, 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', 337 407 ... 'writer': u'1', 'article': u'Hello.'}) 338 408 >>> new_art = f.save() … … 344 414 345 415 Create 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', 348 420 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 349 421 >>> new_art = f.save() … … 355 427 356 428 Create 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', 359 433 ... 'writer': u'1', 'article': u'Test.'}) 360 434 >>> new_art = f.save() … … 367 441 Create a new article, with categories, via the form, but use commit=False. 368 442 The 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', 371 447 ... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 372 448 >>> new_art = f.save(commit=False) … … 387 463 [<Category: Entertainment>, <Category: It's a test>] 388 464 389 Here, we define a custom Form. Because it happens to have the same fields as390 the Category model, we can use save_instance() to apply its changes to an465 Here, we define a custom ModelForm. Because it happens to have the same fields as 466 the Category model, we can just call the form's save() to apply its changes to an 391 467 existing Category instance. 392 >>> class ShortCategory( Form):468 >>> class ShortCategory(ModelForm): 393 469 ... name = CharField(max_length=5) 394 470 ... slug = CharField(max_length=5) … … 399 475 >>> cat.id 400 476 3 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() 403 479 <Category: Third> 404 480 >>> Category.objects.get(id=3) … … 408 484 at runtime, based on the data in the database when the form is displayed, not 409 485 the 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) 412 490
