summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/forms/forms.py4
-rw-r--r--docs/ref/forms/api.txt18
-rw-r--r--docs/releases/1.7.txt4
-rw-r--r--docs/topics/forms/modelforms.txt6
-rw-r--r--tests/model_forms/tests.py20
5 files changed, 39 insertions, 13 deletions
diff --git a/django/forms/forms.py b/django/forms/forms.py
index f868165977..b5cf17f4eb 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -92,8 +92,8 @@ class DeclarativeFieldsMetaclass(MediaDefiningClass):
declared_fields.update(base.declared_fields)
# Field shadowing.
- for attr in base.__dict__.keys():
- if attr in declared_fields:
+ for attr, value in base.__dict__.items():
+ if value is None and attr in declared_fields:
declared_fields.pop(attr)
new_class.base_fields = declared_fields
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 950bd3a088..10e85b4019 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -982,10 +982,20 @@ classes::
.. versionadded:: 1.7
-* It's possible to opt-out from a ``Field`` inherited from a parent class by
- shadowing it. While any non-``Field`` value works for this purpose, it's
- recommended to use ``None`` to make it explicit that a field is being
- nullified.
+* It's possible to declaratively remove a ``Field`` inherited from a parent
+ class by setting the name to be ``None`` on the subclass. For example::
+
+ >>> from django import forms
+
+ >>> class ParentForm(forms.Form):
+ ... name = forms.CharField()
+ ... age = forms.IntegerField()
+
+ >>> class ChildForm(ParentForm):
+ ... name = None
+
+ >>> ChildForm().fields.keys()
+ ... ['age']
.. _form-prefix:
diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt
index a8e600a04b..0b43b97d73 100644
--- a/docs/releases/1.7.txt
+++ b/docs/releases/1.7.txt
@@ -544,8 +544,8 @@ Forms
inheriting from both ``Form`` and ``ModelForm`` simultaneously have been
removed as long as ``ModelForm`` appears first in the MRO.
-* It's now possible to opt-out from a ``Form`` field declared in a parent class
- by shadowing it with a non-``Field`` value.
+* It's now possible to remove a field from a ``Form`` when subclassing by
+ setting the name to ``None``.
* The new :meth:`~django.forms.Form.add_error()` method allows adding errors
to specific form fields.
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
index e96345f155..4ac4dcea90 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -666,10 +666,8 @@ There are a couple of things to note, however.
.. versionadded:: 1.7
-* It's possible to opt-out from a ``Field`` inherited from a parent class by
- shadowing it. While any non-``Field`` value works for this purpose, it's
- recommended to use ``None`` to make it explicit that a field is being
- nullified.
+* It's possible to declaratively remove a ``Field`` inherited from a parent class by
+ setting the name to be ``None`` on the subclass.
You can only use this technique to opt out from a field defined declaratively
by a parent class; it won't prevent the ``ModelForm`` metaclass from generating
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index c3b4c339c0..de96246c6f 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -2227,7 +2227,7 @@ class ModelFormInheritanceTests(TestCase):
self.assertEqual(list(ModelForm().fields.keys()), ['name', 'age'])
- def test_field_shadowing(self):
+ def test_field_removal(self):
class ModelForm(forms.ModelForm):
class Meta:
model = Writer
@@ -2250,6 +2250,24 @@ class ModelFormInheritanceTests(TestCase):
self.assertEqual(list(type(str('NewForm'), (ModelForm, Form, Mixin), {})().fields.keys()), ['name', 'age'])
self.assertEqual(list(type(str('NewForm'), (ModelForm, Form), {'age': None})().fields.keys()), ['name'])
+ def test_field_removal_name_clashes(self):
+ """Regression test for https://code.djangoproject.com/ticket/22510."""
+
+ class MyForm(forms.ModelForm):
+ media = forms.CharField()
+
+ class Meta:
+ model = Writer
+ fields = '__all__'
+
+ class SubForm(MyForm):
+ media = None
+
+ self.assertIn('media', MyForm().fields)
+ self.assertNotIn('media', SubForm().fields)
+ self.assertTrue(hasattr(MyForm, 'media'))
+ self.assertTrue(hasattr(SubForm, 'media'))
+
class StumpJokeForm(forms.ModelForm):
class Meta: