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 2cfd4ec241..0b4e0e955e 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 4cf8e7d828..4fef753172 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -964,10 +964,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 44ccd022b6..4c01659ba6 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 9cd0223ea4..bfee475b88 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -674,10 +674,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 9a88ff60f0..dc912c0cd6 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -2267,7 +2267,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
@@ -2290,6 +2290,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: