Commit ee4edb1e authored by Tim Graham's avatar Tim Graham
Browse files

Made ModelForms raise ImproperlyConfigured if the list of fields is not specified.

Also applies to modelform(set)_factory and generic model views.

refs #19733.
parent 1c8dbb0c
Loading
Loading
Loading
Loading
+14 −24
Original line number Diff line number Diff line
@@ -6,10 +6,9 @@ and database field objects.
from __future__ import unicode_literals

from collections import OrderedDict
import warnings

from django.core.exceptions import (
    ValidationError, NON_FIELD_ERRORS, FieldError)
    ImproperlyConfigured, ValidationError, NON_FIELD_ERRORS, FieldError)
from django.forms.fields import Field, ChoiceField
from django.forms.forms import DeclarativeFieldsMetaclass, BaseForm
from django.forms.formsets import BaseFormSet, formset_factory
@@ -17,7 +16,6 @@ from django.forms.utils import ErrorList
from django.forms.widgets import (SelectMultiple, HiddenInput,
    MultipleHiddenInput)
from django.utils import six
from django.utils.deprecation import RemovedInDjango18Warning
from django.utils.encoding import smart_text, force_text
from django.utils.text import get_text_list, capfirst
from django.utils.translation import ugettext_lazy as _, ugettext
@@ -266,12 +264,11 @@ class ModelFormMetaclass(DeclarativeFieldsMetaclass):
        if opts.model:
            # If a model is defined, extract form fields from it.
            if opts.fields is None and opts.exclude is None:
                # This should be some kind of assertion error once deprecation
                # cycle is complete.
                warnings.warn("Creating a ModelForm without either the 'fields' attribute "
                              "or the 'exclude' attribute is deprecated - form %s "
                              "needs updating" % name,
                              RemovedInDjango18Warning, stacklevel=2)
                raise ImproperlyConfigured(
                    "Creating a ModelForm without either the 'fields' attribute "
                    "or the 'exclude' attribute is prohibited; form %s "
                    "needs updating." % name
                )

            if opts.fields == ALL_FIELDS:
                # Sentinel for fields_for_model to indicate "get the list of
@@ -528,14 +525,12 @@ def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
        'formfield_callback': formfield_callback
    }

    # The ModelFormMetaclass will trigger a similar warning/error, but this will
    # be difficult to debug for code that needs updating, so we produce the
    # warning here too.
    if (getattr(Meta, 'fields', None) is None and
            getattr(Meta, 'exclude', None) is None):
        warnings.warn("Calling modelform_factory without defining 'fields' or "
                      "'exclude' explicitly is deprecated",
                      RemovedInDjango18Warning, stacklevel=2)
        raise ImproperlyConfigured(
            "Calling modelform_factory without defining 'fields' or "
            "'exclude' explicitly is prohibited."
        )

    # Instatiate type(form) in order to use the same metaclass as form.
    return type(form)(class_name, (form,), form_class_attrs)
@@ -814,20 +809,15 @@ def modelformset_factory(model, form=ModelForm, formfield_callback=None,
    """
    Returns a FormSet class for the given Django model class.
    """
    # modelform_factory will produce the same warning/error, but that will be
    # difficult to debug for code that needs upgrading, so we produce the
    # warning here too. This logic is reproducing logic inside
    # modelform_factory, but it can be removed once the deprecation cycle is
    # complete, since the validation exception will produce a helpful
    # stacktrace.
    meta = getattr(form, 'Meta', None)
    if meta is None:
        meta = type(str('Meta'), (object,), {})
    if (getattr(meta, 'fields', fields) is None and
            getattr(meta, 'exclude', exclude) is None):
        warnings.warn("Calling modelformset_factory without defining 'fields' or "
                      "'exclude' explicitly is deprecated",
                      RemovedInDjango18Warning, stacklevel=2)
        raise ImproperlyConfigured(
            "Calling modelformset_factory without defining 'fields' or "
            "'exclude' explicitly is prohibited."
        )

    form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
                             formfield_callback=formfield_callback,
+4 −6
Original line number Diff line number Diff line
import warnings

from django.core.exceptions import ImproperlyConfigured
from django.forms import models as model_forms
from django.http import HttpResponseRedirect
from django.utils.deprecation import RemovedInDjango18Warning
from django.utils.encoding import force_text
from django.views.generic.base import TemplateResponseMixin, ContextMixin, View
from django.views.generic.detail import (SingleObjectMixin,
@@ -112,9 +109,10 @@ class ModelFormMixin(FormMixin, SingleObjectMixin):
                model = self.get_queryset().model

            if self.fields is None:
                warnings.warn("Using ModelFormMixin (base class of %s) without "
                              "the 'fields' attribute is deprecated." % self.__class__.__name__,
                              RemovedInDjango18Warning)
                raise ImproperlyConfigured(
                    "Using ModelFormMixin (base class of %s) without "
                    "the 'fields' attribute is prohibited." % self.__class__.__name__
                )

            return model_forms.modelform_factory(model, fields=self.fields)

+7 −4
Original line number Diff line number Diff line
@@ -129,15 +129,18 @@ ModelFormMixin

    .. attribute:: fields

        .. versionadded:: 1.6

        A list of names of fields. This is interpreted the same way as the
        ``Meta.fields`` attribute of :class:`~django.forms.ModelForm`.

        This is a required attribute if you are generating the form class
        automatically (e.g. using ``model``). Omitting this attribute will
        result in all fields being used, but this behavior is deprecated
        and will be removed in Django 1.8.
        result in an :exc:`~django.core.exceptions.ImproperlyConfigured`
        exception.

        .. versionchanged:: 1.8

            Previously, omitting this attribute was allowed and resulted in
            a form with all fields of the model.

    .. attribute:: success_url

+6 −6
Original line number Diff line number Diff line
@@ -34,16 +34,16 @@ Model Form Functions

    See :ref:`modelforms-factory` for example usage.

    .. versionchanged:: 1.6

    You must provide the list of fields explicitly, either via keyword arguments
    ``fields`` or ``exclude``, or the corresponding attributes on the form's
    inner ``Meta`` class. See :ref:`modelforms-selecting-fields` for more
    information. Omitting any definition of the fields to use will result in all
    fields being used, but this behavior is deprecated.
    information. Omitting any definition of the fields to use will result in
    an :exc:`~django.core.exceptions.ImproperlyConfigured` exception.

    .. versionchanged:: 1.8

    The ``localized_fields``, ``labels``, ``help_texts``, and
    ``error_messages`` parameters were added.
        Previously, omitting the list of fields was allowed and resulted in
        a form with all fields of the model.

.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False, localized_fields=None, labels=None, help_texts=None, error_messages=None)

+7 −8
Original line number Diff line number Diff line
@@ -128,16 +128,15 @@ here; we don't have to write any logic ourselves::
    We have to use :func:`~django.core.urlresolvers.reverse_lazy` here, not
    just ``reverse`` as the urls are not loaded when the file is imported.

.. versionchanged:: 1.6
The ``fields`` attribute works the same way as the ``fields`` attribute on the
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the
form class in another way, the attribute is required and the view will raise
an :exc:`~django.core.exceptions.ImproperlyConfigured` exception if it's not.

In Django 1.6, the ``fields`` attribute was added, which works the same way as
the ``fields`` attribute on the inner ``Meta`` class on
:class:`~django.forms.ModelForm`.

Omitting the fields attribute will work as previously, but is deprecated and
this attribute will be required from 1.8 (unless you define the form class in
another way).
.. versionchanged:: 1.8

    Omitting the ``fields`` attribute was previously allowed and resulted in a
    form with all of the model's fields.

Finally, we hook these new views into the URLconf::

Loading