1
0
mirror of https://github.com/django/django.git synced 2025-11-07 07:15:35 +00:00

Fixed #28345 -- Applied limit_choices_to during ModelForm.__init__().

field_for_model() now has an additional keyword argument,
apply_limit_choices_to, allowing it to continue to be used to create
form fields dynamically after ModelForm.__init__() is called.

Thanks Tim Graham for the review.
This commit is contained in:
Jon Dufresne
2017-06-28 20:30:19 -07:00
parent 5cbcb36839
commit a1be12fe19
3 changed files with 37 additions and 12 deletions

View File

@@ -93,10 +93,18 @@ def model_to_dict(instance, fields=None, exclude=None):
return data
def apply_limit_choices_to_to_formfield(formfield):
"""Apply limit_choices_to to the formfield's queryset if needed."""
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:
formfield.queryset = formfield.queryset.complex_filter(limit_choices_to)
def fields_for_model(model, fields=None, exclude=None, widgets=None,
formfield_callback=None, localized_fields=None,
labels=None, help_texts=None, error_messages=None,
field_classes=None):
field_classes=None, *, apply_limit_choices_to=True):
"""
Return an ``OrderedDict`` containing form fields for the given model.
@@ -123,6 +131,9 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None,
``field_classes`` is a dictionary of model field names mapped to a form
field class.
``apply_limit_choices_to`` is a boolean indicating if limit_choices_to
should be applied to a field's queryset.
"""
field_list = []
ignored = []
@@ -166,11 +177,8 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None,
formfield = formfield_callback(f, **kwargs)
if formfield:
# Apply ``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:
formfield.queryset = formfield.queryset.complex_filter(limit_choices_to)
if apply_limit_choices_to:
apply_limit_choices_to_to_formfield(formfield)
field_list.append((f.name, formfield))
else:
ignored.append(f.name)
@@ -241,11 +249,13 @@ class ModelFormMetaclass(DeclarativeFieldsMetaclass):
# fields from the model"
opts.fields = None
fields = fields_for_model(opts.model, opts.fields, opts.exclude,
opts.widgets, formfield_callback,
opts.localized_fields, opts.labels,
opts.help_texts, opts.error_messages,
opts.field_classes)
fields = fields_for_model(
opts.model, opts.fields, opts.exclude, opts.widgets,
formfield_callback, opts.localized_fields, opts.labels,
opts.help_texts, opts.error_messages, opts.field_classes,
# limit_choices_to will be applied during ModelForm.__init__().
apply_limit_choices_to=False,
)
# make sure opts.fields doesn't specify an invalid field
none_model_fields = [k for k, v in fields.items() if not v]
@@ -291,6 +301,8 @@ class BaseModelForm(BaseForm):
data, files, auto_id, prefix, object_data, error_class,
label_suffix, empty_permitted, use_required_attribute=use_required_attribute,
)
for formfield in self.fields.values():
apply_limit_choices_to_to_formfield(formfield)
def _get_validation_exclusions(self):
"""