Kaydet (Commit) b16dd1fe authored tarafından Loic Bistuer's avatar Loic Bistuer

Fixed #8620 -- Updated the Form metaclass to support excluding fields by shadowing them.

üst ac5ec7b8
...@@ -90,6 +90,11 @@ class DeclarativeFieldsMetaclass(MediaDefiningClass): ...@@ -90,6 +90,11 @@ class DeclarativeFieldsMetaclass(MediaDefiningClass):
if hasattr(base, 'declared_fields'): if hasattr(base, 'declared_fields'):
declared_fields.update(base.declared_fields) declared_fields.update(base.declared_fields)
# Field shadowing.
for attr in base.__dict__.keys():
if attr in declared_fields:
declared_fields.pop(attr)
new_class.base_fields = declared_fields new_class.base_fields = declared_fields
new_class.declared_fields = declared_fields new_class.declared_fields = declared_fields
......
...@@ -854,6 +854,13 @@ classes:: ...@@ -854,6 +854,13 @@ classes::
<li>Instrument: <input type="text" name="instrument" /></li> <li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li> <li>Haircut type: <input type="text" name="haircut_type" /></li>
.. 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.
.. _form-prefix: .. _form-prefix:
Prefixes for forms Prefixes for forms
......
...@@ -293,6 +293,9 @@ Forms ...@@ -293,6 +293,9 @@ Forms
inheriting from both ``Form`` and ``ModelForm`` simultaneously have been inheriting from both ``Form`` and ``ModelForm`` simultaneously have been
removed as long as ``ModelForm`` appears first in the MRO. 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.
Internationalization Internationalization
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
......
...@@ -651,6 +651,18 @@ There are a couple of things to note, however. ...@@ -651,6 +651,18 @@ There are a couple of things to note, however.
because these classes rely on different metaclasses and a class can only have because these classes rely on different metaclasses and a class can only have
one metaclass. one metaclass.
.. 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.
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
a default field. To opt-out from default fields, see
:ref:`controlling-fields-with-fields-and-exclude`.
.. _modelforms-factory: .. _modelforms-factory:
ModelForm factory function ModelForm factory function
...@@ -749,6 +761,8 @@ instances of the model, you can specify an empty QuerySet:: ...@@ -749,6 +761,8 @@ instances of the model, you can specify an empty QuerySet::
>>> AuthorFormSet(queryset=Author.objects.none()) >>> AuthorFormSet(queryset=Author.objects.none())
.. _controlling-fields-with-fields-and-exclude:
Controlling which fields are used with ``fields`` and ``exclude`` Controlling which fields are used with ``fields`` and ``exclude``
----------------------------------------------------------------- -----------------------------------------------------------------
......
...@@ -1815,3 +1815,26 @@ class ModelFormInheritanceTests(TestCase): ...@@ -1815,3 +1815,26 @@ class ModelFormInheritanceTests(TestCase):
fields = '__all__' fields = '__all__'
self.assertEqual(list(ModelForm().fields.keys()), ['name', 'age']) self.assertEqual(list(ModelForm().fields.keys()), ['name', 'age'])
def test_field_shadowing(self):
class ModelForm(forms.ModelForm):
class Meta:
model = Writer
fields = '__all__'
class Mixin(object):
age = None
class Form(forms.Form):
age = forms.IntegerField()
class Form2(forms.Form):
foo = forms.IntegerField()
self.assertEqual(list(ModelForm().fields.keys()), ['name'])
self.assertEqual(list(type(str('NewForm'), (Mixin, Form), {})().fields.keys()), [])
self.assertEqual(list(type(str('NewForm'), (Form2, Mixin, Form), {})().fields.keys()), ['foo'])
self.assertEqual(list(type(str('NewForm'), (Mixin, ModelForm, Form), {})().fields.keys()), ['name'])
self.assertEqual(list(type(str('NewForm'), (ModelForm, Mixin, Form), {})().fields.keys()), ['name'])
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'])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment