Fixed #23795 -- Fixed a regression in custom form fields
Custom form fields having a `queryset` attribute but no `limit_choices_to` could no longer be used in ModelForms. Refs #2445. Thanks to artscoop for the report.
This commit is contained in:
parent
11b7680d0e
commit
bfb11b9562
|
@ -181,17 +181,6 @@ class Field(six.with_metaclass(RenameFieldMethods, object)):
|
||||||
"""
|
"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_limit_choices_to(self):
|
|
||||||
"""
|
|
||||||
Returns ``limit_choices_to`` for this form field.
|
|
||||||
|
|
||||||
If it is a callable, it will be invoked and the result will be
|
|
||||||
returned.
|
|
||||||
"""
|
|
||||||
if callable(self.limit_choices_to):
|
|
||||||
return self.limit_choices_to()
|
|
||||||
return self.limit_choices_to
|
|
||||||
|
|
||||||
def has_changed(self, initial, data):
|
def has_changed(self, initial, data):
|
||||||
"""
|
"""
|
||||||
Return True if data differs from initial.
|
Return True if data differs from initial.
|
||||||
|
|
|
@ -328,11 +328,9 @@ class BaseModelForm(BaseForm):
|
||||||
# Apply ``limit_choices_to`` to each field.
|
# Apply ``limit_choices_to`` to each field.
|
||||||
for field_name in self.fields:
|
for field_name in self.fields:
|
||||||
formfield = self.fields[field_name]
|
formfield = self.fields[field_name]
|
||||||
if hasattr(formfield, 'queryset'):
|
if hasattr(formfield, 'queryset') and hasattr(formfield, 'get_limit_choices_to'):
|
||||||
limit_choices_to = formfield.limit_choices_to
|
limit_choices_to = formfield.get_limit_choices_to()
|
||||||
if limit_choices_to is not None:
|
if limit_choices_to is not None:
|
||||||
if callable(limit_choices_to):
|
|
||||||
limit_choices_to = limit_choices_to()
|
|
||||||
formfield.queryset = formfield.queryset.complex_filter(limit_choices_to)
|
formfield.queryset = formfield.queryset.complex_filter(limit_choices_to)
|
||||||
|
|
||||||
def _get_validation_exclusions(self):
|
def _get_validation_exclusions(self):
|
||||||
|
@ -1133,6 +1131,17 @@ class ModelChoiceField(ChoiceField):
|
||||||
self.choice_cache = None
|
self.choice_cache = None
|
||||||
self.to_field_name = to_field_name
|
self.to_field_name = to_field_name
|
||||||
|
|
||||||
|
def get_limit_choices_to(self):
|
||||||
|
"""
|
||||||
|
Returns ``limit_choices_to`` for this form field.
|
||||||
|
|
||||||
|
If it is a callable, it will be invoked and the result will be
|
||||||
|
returned.
|
||||||
|
"""
|
||||||
|
if callable(self.limit_choices_to):
|
||||||
|
return self.limit_choices_to()
|
||||||
|
return self.limit_choices_to
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
result = super(ChoiceField, self).__deepcopy__(memo)
|
result = super(ChoiceField, self).__deepcopy__(memo)
|
||||||
# Need to force a new ModelChoiceIterator to be created, bug #11183
|
# Need to force a new ModelChoiceIterator to be created, bug #11183
|
||||||
|
|
|
@ -52,3 +52,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a migration serializing bug involving ``float("nan")`` and
|
* Fixed a migration serializing bug involving ``float("nan")`` and
|
||||||
``float("inf")`` (:ticket:23770:).
|
``float("inf")`` (:ticket:23770:).
|
||||||
|
|
||||||
|
* Fixed a regression where custom form fields having a ``queryset`` attribute
|
||||||
|
but no ``limit_choices_to`` could not be used in a
|
||||||
|
:class:`~django.forms.ModelForm` (:ticket:`23795`).
|
||||||
|
|
|
@ -2377,6 +2377,17 @@ class StumpJokeForm(forms.ModelForm):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldWithQuerysetButNoLimitChoicesTo(forms.Field):
|
||||||
|
queryset = 42
|
||||||
|
|
||||||
|
|
||||||
|
class StumpJokeWithCustomFieldForm(forms.ModelForm):
|
||||||
|
custom = CustomFieldWithQuerysetButNoLimitChoicesTo()
|
||||||
|
class Meta:
|
||||||
|
model = StumpJoke
|
||||||
|
fields = () # We don't need any fields from the model
|
||||||
|
|
||||||
|
|
||||||
class LimitChoicesToTest(TestCase):
|
class LimitChoicesToTest(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests the functionality of ``limit_choices_to``.
|
Tests the functionality of ``limit_choices_to``.
|
||||||
|
@ -2407,6 +2418,14 @@ class LimitChoicesToTest(TestCase):
|
||||||
self.assertIn(self.threepwood, stumpjokeform.fields['has_fooled_today'].queryset)
|
self.assertIn(self.threepwood, stumpjokeform.fields['has_fooled_today'].queryset)
|
||||||
self.assertNotIn(self.marley, stumpjokeform.fields['has_fooled_today'].queryset)
|
self.assertNotIn(self.marley, stumpjokeform.fields['has_fooled_today'].queryset)
|
||||||
|
|
||||||
|
def test_custom_field_with_queryset_but_no_limit_choices_to(self):
|
||||||
|
"""
|
||||||
|
Regression test for #23795: Make sure a custom field with a `queryset`
|
||||||
|
attribute but no `limit_choices_to` still works.
|
||||||
|
"""
|
||||||
|
f = StumpJokeWithCustomFieldForm()
|
||||||
|
self.assertEqual(f.fields['custom'].queryset, 42)
|
||||||
|
|
||||||
|
|
||||||
class FormFieldCallbackTests(TestCase):
|
class FormFieldCallbackTests(TestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue