summaryrefslogtreecommitdiff
path: root/django/forms
diff options
context:
space:
mode:
authorLuke Plant <L.Plant.98@cantab.net>2013-02-21 21:56:55 +0000
committerLuke Plant <L.Plant.98@cantab.net>2013-05-09 16:44:36 +0100
commitf026a519aea8f3ea7ca339bfbbb007e1ee0068b0 (patch)
tree882e594178a78d507ede36c2c9b0b8d5a9305561 /django/forms
parent1e37cb37cec330a6b78925e2ef5589817428d09a (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 'django/forms')
-rw-r--r--django/forms/models.py57
1 files changed, 55 insertions, 2 deletions
diff --git a/django/forms/models.py b/django/forms/models.py
index 5e7797809a..af5cda8faf 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -5,6 +5,8 @@ and database field objects.
from __future__ import absolute_import, unicode_literals
+import warnings
+
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, FieldError
from django.forms.fields import Field, ChoiceField
from django.forms.forms import BaseForm, get_declared_fields
@@ -22,8 +24,12 @@ from django.utils.translation import ugettext_lazy as _, ugettext
__all__ = (
'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
'save_instance', 'ModelChoiceField', 'ModelMultipleChoiceField',
+ 'ALL_FIELDS',
)
+ALL_FIELDS = '__all__'
+
+
def construct_instance(form, instance, fields=None, exclude=None):
"""
Constructs and returns a model instance from the bound ``form``'s
@@ -211,7 +217,7 @@ class ModelFormMetaclass(type):
# of ('foo',)
for opt in ['fields', 'exclude']:
value = getattr(opts, opt)
- if isinstance(value, six.string_types):
+ if isinstance(value, six.string_types) and value != ALL_FIELDS:
msg = ("%(model)s.Meta.%(opt)s cannot be a string. "
"Did you mean to type: ('%(value)s',)?" % {
'model': new_class.__name__,
@@ -222,6 +228,20 @@ class ModelFormMetaclass(type):
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,
+ PendingDeprecationWarning)
+
+ if opts.fields == ALL_FIELDS:
+ # sentinel for fields_for_model to indicate "get the list of
+ # fields from the model"
+ opts.fields = None
+
fields = fields_for_model(opts.model, opts.fields,
opts.exclude, opts.widgets, formfield_callback)
# make sure opts.fields doesn't specify an invalid field
@@ -394,7 +414,8 @@ def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
Returns a ModelForm containing form fields for the given model.
``fields`` is an optional list of field names. If provided, only the named
- fields will be included in the returned fields.
+ fields will be included in the returned fields. If omitted or '__all__',
+ all fields will be used.
``exclude`` is an optional list of field names. If provided, the named
fields will be excluded from the returned fields, even if they are listed
@@ -434,6 +455,15 @@ 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",
+ PendingDeprecationWarning, stacklevel=2)
+
# Instatiate type(form) in order to use the same metaclass as form.
return type(form)(class_name, (form,), form_class_attrs)
@@ -701,6 +731,21 @@ 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",
+ PendingDeprecationWarning, stacklevel=2)
+
form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
formfield_callback=formfield_callback,
widgets=widgets)
@@ -1091,3 +1136,11 @@ class ModelMultipleChoiceField(ModelChoiceField):
initial_set = set([force_text(value) for value in self.prepare_value(initial)])
data_set = set([force_text(value) for value in data])
return data_set != initial_set
+
+
+def modelform_defines_fields(form_class):
+ return (form_class is not None and (
+ hasattr(form_class, '_meta') and
+ (form_class._meta.fields is not None or
+ form_class._meta.exclude is not None)
+ ))