Fixed #8620 -- Updated the Form metaclass to support excluding fields by shadowing them.
This commit is contained in:
parent
ac5ec7b8bc
commit
b16dd1fe01
|
@ -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::
|
||||||
<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
|
||||||
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.
|
||||||
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::
|
||||||
>>> 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):
|
||||||
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'])
|
||||||
|
|
Loading…
Reference in New Issue