diff options
| author | Luke Plant <L.Plant.98@cantab.net> | 2013-02-21 21:56:55 +0000 |
|---|---|---|
| committer | Luke Plant <L.Plant.98@cantab.net> | 2013-05-09 16:44:36 +0100 |
| commit | f026a519aea8f3ea7ca339bfbbb007e1ee0068b0 (patch) | |
| tree | 882e594178a78d507ede36c2c9b0b8d5a9305561 /docs/topics/forms | |
| parent | 1e37cb37cec330a6b78925e2ef5589817428d09a (diff) | |
Fixed #19733 - deprecated ModelForms without 'fields' or 'exclude', and added '__all__' shortcut
This also updates all dependent functionality, including modelform_factory
and modelformset_factory, and the generic views `ModelFormMixin`,
`CreateView` and `UpdateView` which gain a new `fields` attribute.
Diffstat (limited to 'docs/topics/forms')
| -rw-r--r-- | docs/topics/forms/modelforms.txt | 163 |
1 files changed, 83 insertions, 80 deletions
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index eaf2bbbaf2..e58dade736 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -28,6 +28,7 @@ For example:: >>> class ArticleForm(ModelForm): ... class Meta: ... model = Article + ... fields = ['pub_date', 'headline', 'content', 'reporter'] # Creating a form to add an article. >>> form = ArticleForm() @@ -39,11 +40,13 @@ For example:: Field types ----------- -The generated ``Form`` class will have a form field for every model field. Each -model field has a corresponding default form field. For example, a -``CharField`` on a model is represented as a ``CharField`` on a form. A -model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is -the full list of conversions: +The generated ``Form`` class will have a form field for every model field +specified, in the order specified in the ``fields`` attribute. + +Each model field has a corresponding default form field. For example, a +``CharField`` on a model is represented as a ``CharField`` on a form. A model +``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is the +full list of conversions: =============================== ======================================== Model field Form field @@ -168,10 +171,13 @@ Consider this set of models:: class AuthorForm(ModelForm): class Meta: model = Author + fields = ['name', 'title', 'birth_date'] class BookForm(ModelForm): class Meta: model = Book + fields = ['name', 'authors'] + With these models, the ``ModelForm`` subclasses above would be roughly equivalent to this (the only difference being the ``save()`` method, which @@ -288,47 +294,66 @@ method is used to determine whether a form requires multipart file upload (and hence whether ``request.FILES`` must be passed to the form), etc. See :ref:`binding-uploaded-files` for more information. -Using a subset of fields on the form ------------------------------------- +.. _modelforms-selecting-fields: -In some cases, you may not want all the model fields to appear on the generated -form. There are three ways of telling ``ModelForm`` to use only a subset of the -model fields: +Selecting the fields to use +--------------------------- -1. Set ``editable=False`` on the model field. As a result, *any* form - created from the model via ``ModelForm`` will not include that - field. +It is strongly recommended that you explicitly set all fields that should be +edited in the form using the ``fields`` attribute. Failure to do so can easily +lead to security problems when a form unexpectedly allows a user to set certain +fields, especially when new fields are added to a model. Depending on how the +form is rendered, the problem may not even be visible on the web page. -2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` - class. This attribute, if given, should be a list of field names - to include in the form. The order in which the fields names are specified - in that list is respected when the form renders them. +The alternative approach would be to include all fields automatically, or +blacklist only some. This fundamental approach is known to be much less secure +and has led to serious exploits on major websites (e.g. `GitHub +<https://github.com/blog/1068-public-key-security-vulnerability-and-mitigation>`_). -3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` - class. This attribute, if given, should be a list of field names - to exclude from the form. +There are, however, two shortcuts available for cases where you can guarantee +these security concerns do not apply to you: -For example, if you want a form for the ``Author`` model (defined -above) that includes only the ``name`` and ``birth_date`` fields, you would -specify ``fields`` or ``exclude`` like this:: +1. Set the ``fields`` attribute to the special value ``'__all__'`` to indicate + that all fields in the model should be used. For example:: - class PartialAuthorForm(ModelForm): - class Meta: - model = Author - fields = ('name', 'birth_date') + class AuthorForm(ModelForm): + class Meta: + model = Author + fields = '__all__' - class PartialAuthorForm(ModelForm): - class Meta: - model = Author - exclude = ('title',) +2. Set the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` class to + a list of fields to be excluded from the form. + + For example:: + + class PartialAuthorForm(ModelForm): + class Meta: + model = Author + exclude = ['title'] + + Since the ``Author`` model has the 3 fields ``name``, ``title`` and + ``birth_date``, this will result in the fields ``name`` and ``birth_date`` + being present on the form. + +If either of these are used, the order the fields appear in the form will be the +order the fields are defined in the model, with ``ManyToManyField`` instances +appearing last. + +In addition, Django applies the following rule: if you set ``editable=False`` on +the model field, *any* form created from the model via ``ModelForm`` will not +include that field. + +.. versionchanged:: 1.6 + + Before version 1.6, the ``'__all__'`` shortcut did not exist, but omitting + the ``fields`` attribute had the same effect. Omitting both ``fields`` and + ``exclude`` is now deprecated, but will continue to work as before until + version 1.8 -Since the Author model has only 3 fields, 'name', 'title', and -'birth_date', the forms above will contain exactly the same fields. .. note:: - If you specify ``fields`` or ``exclude`` when creating a form with - ``ModelForm``, then the fields that are not in the resulting form + Any fields not included in a form by the above logic will not be set by the form's ``save()`` method. Also, if you manually add the excluded fields back to the form, they will not be initialized from the model instance. @@ -401,15 +426,19 @@ field, you could do the following:: class Meta: model = Article + fields = ['pub_date', 'headline', 'content', 'reporter'] + If you want to override a field's default label, then specify the ``label`` parameter when declaring the form field:: - >>> class ArticleForm(ModelForm): - ... pub_date = DateField(label='Publication date') - ... - ... class Meta: - ... model = Article + class ArticleForm(ModelForm): + pub_date = DateField(label='Publication date') + + class Meta: + model = Article + fields = ['pub_date', 'headline', 'content', 'reporter'] + .. note:: @@ -436,6 +465,7 @@ parameter when declaring the form field:: class Meta: model = Article + fields = ['headline', 'content'] You must ensure that the type of the form field can be used to set the contents of the corresponding model field. When they are not compatible, @@ -444,30 +474,6 @@ parameter when declaring the form field:: See the :doc:`form field documentation </ref/forms/fields>` for more information on fields and their arguments. -Changing the order of fields ----------------------------- - -By default, a ``ModelForm`` will render fields in the same order that they are -defined on the model, with ``ManyToManyField`` instances appearing last. If -you want to change the order in which fields are rendered, you can use the -``fields`` attribute on the ``Meta`` class. - -The ``fields`` attribute defines the subset of model fields that will be -rendered, and the order in which they will be rendered. For example given this -model:: - - class Book(models.Model): - author = models.ForeignKey(Author) - title = models.CharField(max_length=100) - -the ``author`` field would be rendered first. If we wanted the title field -to be rendered first, we could specify the following ``ModelForm``:: - - >>> class BookForm(ModelForm): - ... class Meta: - ... model = Book - ... fields = ('title', 'author') - .. _overriding-modelform-clean-method: Overriding the clean() method @@ -550,21 +556,19 @@ definition. This may be more convenient if you do not have many customizations to make:: >>> from django.forms.models import modelform_factory - >>> BookForm = modelform_factory(Book) + >>> BookForm = modelform_factory(Book, fields=("author", "title")) This can also be used to make simple modifications to existing forms, for -example by specifying which fields should be displayed:: - - >>> Form = modelform_factory(Book, form=BookForm, fields=("author",)) - -... or which fields should be excluded:: - - >>> Form = modelform_factory(Book, form=BookForm, exclude=("title",)) - -You can also specify the widgets to be used for a given field:: +example by specifying the widgets to be used for a given field:: >>> from django.forms import Textarea - >>> Form = modelform_factory(Book, form=BookForm, widgets={"title": Textarea()}) + >>> Form = modelform_factory(Book, form=BookForm, + widgets={"title": Textarea()}) + +The fields to include can be specified using the ``fields`` and ``exclude`` +keyword arguments, or the corresponding attributes on the ``ModelForm`` inner +``Meta`` class. Please see the ``ModelForm`` :ref:`modelforms-selecting-fields` +documentation. .. _model-formsets: @@ -688,11 +692,10 @@ database. If a given instance's data didn't change in the bound data, the instance won't be saved to the database and won't be included in the return value (``instances``, in the above example). -When fields are missing from the form (for example because they have -been excluded), these fields will not be set by the ``save()`` -method. You can find more information about this restriction, which -also holds for regular ``ModelForms``, in `Using a subset of fields on -the form`_. +When fields are missing from the form (for example because they have been +excluded), these fields will not be set by the ``save()`` method. You can find +more information about this restriction, which also holds for regular +``ModelForms``, in `Selecting the fields to use`_. Pass ``commit=False`` to return the unsaved model instances:: |
