[1.7.x] 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.
Backport of bfb11b9562
from master.
Conflicts:
django/forms/fields.py
This commit is contained in:
parent
3e0d7de8a6
commit
606c57a132
|
@ -171,17 +171,6 @@ class Field(object):
|
|||
"""
|
||||
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):
|
||||
"""
|
||||
Return True if data differs from initial.
|
||||
|
|
|
@ -329,11 +329,9 @@ class BaseModelForm(BaseForm):
|
|||
# Apply ``limit_choices_to`` to each field.
|
||||
for field_name in self.fields:
|
||||
formfield = self.fields[field_name]
|
||||
if hasattr(formfield, 'queryset'):
|
||||
limit_choices_to = formfield.limit_choices_to
|
||||
if hasattr(formfield, 'queryset') and hasattr(formfield, 'get_limit_choices_to'):
|
||||
limit_choices_to = formfield.get_limit_choices_to()
|
||||
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)
|
||||
|
||||
def _get_validation_exclusions(self):
|
||||
|
@ -1118,6 +1116,17 @@ class ModelChoiceField(ChoiceField):
|
|||
self.choice_cache = None
|
||||
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):
|
||||
result = super(ChoiceField, self).__deepcopy__(memo)
|
||||
# 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
|
||||
``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`).
|
||||
|
|
|
@ -2345,6 +2345,17 @@ class StumpJokeForm(forms.ModelForm):
|
|||
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):
|
||||
"""
|
||||
Tests the functionality of ``limit_choices_to``.
|
||||
|
@ -2375,6 +2386,14 @@ class LimitChoicesToTest(TestCase):
|
|||
self.assertIn(self.threepwood, 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):
|
||||
|
||||
|
|
Loading…
Reference in New Issue