1"""
2Helper functions for creating Form classes from Django models
3and database field objects.
4"""
5
6from itertools import chain
7
8from django.core.exceptions import (
9 NON_FIELD_ERRORS,
10 FieldError,
11 ImproperlyConfigured,
12 ValidationError,
13)
14from django.core.validators import ProhibitNullCharactersValidator
15from django.db.models.utils import AltersData
16from django.forms.fields import ChoiceField, Field
17from django.forms.forms import BaseForm, DeclarativeFieldsMetaclass
18from django.forms.formsets import BaseFormSet, formset_factory
19from django.forms.utils import ErrorList
20from django.forms.widgets import (
21 HiddenInput,
22 MultipleHiddenInput,
23 RadioSelect,
24 SelectMultiple,
25)
26from django.utils.choices import BaseChoiceIterator
27from django.utils.hashable import make_hashable
28from django.utils.text import capfirst, get_text_list
29from django.utils.translation import gettext
30from django.utils.translation import gettext_lazy as _
31
32__all__ = (
33 "ModelForm",
34 "BaseModelForm",
35 "model_to_dict",
36 "fields_for_model",
37 "ModelChoiceField",
38 "ModelMultipleChoiceField",
39 "ALL_FIELDS",
40 "BaseModelFormSet",
41 "modelformset_factory",
42 "BaseInlineFormSet",
43 "inlineformset_factory",
44 "modelform_factory",
45)
46
47ALL_FIELDS = "__all__"
48
49
50def construct_instance(form, instance, fields=None, exclude=None):
51 """
52 Construct and return a model instance from the bound ``form``'s
53 ``cleaned_data``, but do not save the returned instance to the database.
54 """
55 from django.db import models
56
57 opts = instance._meta
58
59 cleaned_data = form.cleaned_data
60 file_field_list = []
61 for f in opts.fields:
62 if (
63 not f.editable
64 or isinstance(f, models.AutoField)
65 or f.name not in cleaned_data
66 ):
67 continue
68 if fields is not None and f.name not in fields:
69 continue
70 if exclude and f.name in exclude:
71 continue
72 # Leave defaults for fields that aren't in POST data, except for
73 # checkbox inputs because they don't appear in POST data if not checked.
74 if (
75 f.has_default()
76 and form[f.name].field.widget.value_omitted_from_data(
77 form.data, form.files, form.add_prefix(f.name)
78 )
79 and cleaned_data.get(f.name) in form[f.name].field.empty_values
80 ):
81 continue
82 # Defer saving file-type fields until after the other fields, so a
83 # callable upload_to can use the values from other fields.
84 if isinstance(f, models.FileField):
85 file_field_list.append(f)
86 else:
87 f.save_form_data(instance, cleaned_data[f.name])
88
89 for f in file_field_list:
90 f.save_form_data(instance, cleaned_data[f.name])
91
92 return instance
93
94
95# ModelForms #################################################################
96
97
98def model_to_dict(instance, fields=None, exclude=None):
99 """
100 Return a dict containing the data in ``instance`` suitable for passing as
101 a Form's ``initial`` keyword argument.
102
103 ``fields`` is an optional list of field names. If provided, return only the
104 named.
105
106 ``exclude`` is an optional list of field names. If provided, exclude the
107 named from the returned dict, even if they are listed in the ``fields``
108 argument.
109 """
110 opts = instance._meta
111 data = {}
112 for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
113 if not getattr(f, "editable", False):
114 continue
115 if fields is not None and f.name not in fields:
116 continue
117 if exclude and f.name in exclude:
118 continue
119 data[f.name] = f.value_from_object(instance)
120 return data
121
122
123def apply_limit_choices_to_to_formfield(formfield):
124 """Apply limit_choices_to to the formfield's queryset if needed."""
125 from django.db.models import Exists, OuterRef, Q
126
127 if hasattr(formfield, "queryset") and hasattr(formfield, "get_limit_choices_to"):
128 limit_choices_to = formfield.get_limit_choices_to()
129 if limit_choices_to:
130 complex_filter = limit_choices_to
131 if not isinstance(complex_filter, Q):
132 complex_filter = Q(**limit_choices_to)
133 complex_filter &= Q(pk=OuterRef("pk"))
134 # Use Exists() to avoid potential duplicates.
135 formfield.queryset = formfield.queryset.filter(
136 Exists(formfield.queryset.model._base_manager.filter(complex_filter)),
137 )
138
139
140def fields_for_model(
141 model,
142 fields=None,
143 exclude=None,
144 widgets=None,
145 formfield_callback=None,
146 localized_fields=None,
147 labels=None,
148 help_texts=None,
149 error_messages=None,
150 field_classes=None,
151 *,
152 apply_limit_choices_to=True,
153 form_declared_fields=None,
154):
155 """
156 Return a dictionary containing form fields for the given model.
157
158 ``fields`` is an optional list of field names. If provided, return only the
159 named fields.
160
161 ``exclude`` is an optional list of field names. If provided, exclude the
162 named fields from the returned fields, even if they are listed in the
163 ``fields`` argument.
164
165 ``widgets`` is a dictionary of model field names mapped to a widget.
166
167 ``formfield_callback`` is a callable that takes a model field and returns
168 a form field.
169
170 ``localized_fields`` is a list of names of fields which should be localized.
171
172 ``labels`` is a dictionary of model field names mapped to a label.
173
174 ``help_texts`` is a dictionary of model field names mapped to a help text.
175
176 ``error_messages`` is a dictionary of model field names mapped to a
177 dictionary of error messages.
178
179 ``field_classes`` is a dictionary of model field names mapped to a form
180 field class.
181
182 ``apply_limit_choices_to`` is a boolean indicating if limit_choices_to
183 should be applied to a field's queryset.
184
185 ``form_declared_fields`` is a dictionary of form fields created directly on
186 a form.
187 """
188 form_declared_fields = form_declared_fields or {}
189 field_dict = {}
190 ignored = []
191 opts = model._meta
192 # Avoid circular import
193 from django.db.models import Field as ModelField
194
195 sortable_private_fields = [
196 f for f in opts.private_fields if isinstance(f, ModelField)
197 ]
198 for f in sorted(
199 chain(opts.concrete_fields, sortable_private_fields, opts.many_to_many)
200 ):
201 if not getattr(f, "editable", False):
202 if (
203 fields is not None
204 and f.name in fields
205 and (exclude is None or f.name not in exclude)
206 ):
207 raise FieldError(
208 "'%s' cannot be specified for %s model form as it is a "
209 "non-editable field" % (f.name, model.__name__)
210 )
211 continue
212 if fields is not None and f.name not in fields:
213 continue
214 if exclude and f.name in exclude:
215 continue
216 if f.name in form_declared_fields:
217 field_dict[f.name] = form_declared_fields[f.name]
218 continue
219
220 kwargs = {}
221 if widgets and f.name in widgets:
222 kwargs["widget"] = widgets[f.name]
223 if localized_fields == ALL_FIELDS or (
224 localized_fields and f.name in localized_fields
225 ):
226 kwargs["localize"] = True
227 if labels and f.name in labels:
228 kwargs["label"] = labels[f.name]
229 if help_texts and f.name in help_texts:
230 kwargs["help_text"] = help_texts[f.name]
231 if error_messages and f.name in error_messages:
232 kwargs["error_messages"] = error_messages[f.name]
233 if field_classes and f.name in field_classes:
234 kwargs["form_class"] = field_classes[f.name]
235
236 if formfield_callback is None:
237 formfield = f.formfield(**kwargs)
238 elif not callable(formfield_callback):
239 raise TypeError("formfield_callback must be a function or callable")
240 else:
241 formfield = formfield_callback(f, **kwargs)
242
243 if formfield:
244 if apply_limit_choices_to:
245 apply_limit_choices_to_to_formfield(formfield)
246 field_dict[f.name] = formfield
247 else:
248 ignored.append(f.name)
249 if fields:
250 field_dict = {
251 f: field_dict.get(f)
252 for f in fields
253 if (not exclude or f not in exclude) and f not in ignored
254 }
255 return field_dict
256
257
258class ModelFormOptions:
259 def __init__(self, options=None):
260 self.model = getattr(options, "model", None)
261 self.fields = getattr(options, "fields", None)
262 self.exclude = getattr(options, "exclude", None)
263 self.widgets = getattr(options, "widgets", None)
264 self.localized_fields = getattr(options, "localized_fields", None)
265 self.labels = getattr(options, "labels", None)
266 self.help_texts = getattr(options, "help_texts", None)
267 self.error_messages = getattr(options, "error_messages", None)
268 self.field_classes = getattr(options, "field_classes", None)
269 self.formfield_callback = getattr(options, "formfield_callback", None)
270
271
272class ModelFormMetaclass(DeclarativeFieldsMetaclass):
273 def __new__(mcs, name, bases, attrs):
274 new_class = super().__new__(mcs, name, bases, attrs)
275
276 if bases == (BaseModelForm,):
277 return new_class
278
279 opts = new_class._meta = ModelFormOptions(getattr(new_class, "Meta", None))
280
281 # We check if a string was passed to `fields` or `exclude`,
282 # which is likely to be a mistake where the user typed ('foo') instead
283 # of ('foo',)
284 for opt in ["fields", "exclude", "localized_fields"]:
285 value = getattr(opts, opt)
286 if isinstance(value, str) and value != ALL_FIELDS:
287 msg = (
288 "%(model)s.Meta.%(opt)s cannot be a string. "
289 "Did you mean to type: ('%(value)s',)?"
290 % {
291 "model": new_class.__name__,
292 "opt": opt,
293 "value": value,
294 }
295 )
296 raise TypeError(msg)
297
298 if opts.model:
299 # If a model is defined, extract form fields from it.
300 if opts.fields is None and opts.exclude is None:
301 raise ImproperlyConfigured(
302 "Creating a ModelForm without either the 'fields' attribute "
303 "or the 'exclude' attribute is prohibited; form %s "
304 "needs updating." % name
305 )
306
307 if opts.fields == ALL_FIELDS:
308 # Sentinel for fields_for_model to indicate "get the list of
309 # fields from the model"
310 opts.fields = None
311
312 fields = fields_for_model(
313 opts.model,
314 opts.fields,
315 opts.exclude,
316 opts.widgets,
317 opts.formfield_callback,
318 opts.localized_fields,
319 opts.labels,
320 opts.help_texts,
321 opts.error_messages,
322 opts.field_classes,
323 # limit_choices_to will be applied during ModelForm.__init__().
324 apply_limit_choices_to=False,
325 form_declared_fields=new_class.declared_fields,
326 )
327
328 # make sure opts.fields doesn't specify an invalid field
329 none_model_fields = {k for k, v in fields.items() if not v}
330 missing_fields = none_model_fields.difference(new_class.declared_fields)
331 if missing_fields:
332 message = "Unknown field(s) (%s) specified for %s"
333 message %= (", ".join(missing_fields), opts.model.__name__)
334 raise FieldError(message)
335 # Include all the other declared fields.
336 fields.update(new_class.declared_fields)
337 else:
338 fields = new_class.declared_fields
339
340 new_class.base_fields = fields
341
342 return new_class
343
344
345class BaseModelForm(BaseForm, AltersData):
346 def __init__(
347 self,
348 data=None,
349 files=None,
350 auto_id="id_%s",
351 prefix=None,
352 initial=None,
353 error_class=ErrorList,
354 label_suffix=None,
355 empty_permitted=False,
356 instance=None,
357 use_required_attribute=None,
358 renderer=None,
359 ):
360 opts = self._meta
361 if opts.model is None:
362 raise ValueError("ModelForm has no model class specified.")
363 if instance is None:
364 # if we didn't get an instance, instantiate a new one
365 self.instance = opts.model()
366 object_data = {}
367 else:
368 self.instance = instance
369 object_data = model_to_dict(instance, opts.fields, opts.exclude)
370 # if initial was provided, it should override the values from instance
371 if initial is not None:
372 object_data.update(initial)
373 # self._validate_unique will be set to True by BaseModelForm.clean().
374 # It is False by default so overriding self.clean() and failing to call
375 # super will stop validate_unique from being called.
376 self._validate_unique = False
377 super().__init__(
378 data,
379 files,
380 auto_id,
381 prefix,
382 object_data,
383 error_class,
384 label_suffix,
385 empty_permitted,
386 use_required_attribute=use_required_attribute,
387 renderer=renderer,
388 )
389 for formfield in self.fields.values():
390 apply_limit_choices_to_to_formfield(formfield)
391
392 def _get_validation_exclusions(self):
393 """
394 For backwards-compatibility, exclude several types of fields from model
395 validation. See tickets #12507, #12521, #12553.
396 """
397 exclude = set()
398 # Build up a list of fields that should be excluded from model field
399 # validation and unique checks.
400 for f in self.instance._meta.fields:
401 field = f.name
402 # Exclude fields that aren't on the form. The developer may be
403 # adding these values to the model after form validation.
404 if field not in self.fields:
405 exclude.add(f.name)
406
407 # Don't perform model validation on fields that were defined
408 # manually on the form and excluded via the ModelForm's Meta
409 # class. See #12901.
410 elif self._meta.fields and field not in self._meta.fields:
411 exclude.add(f.name)
412 elif self._meta.exclude and field in self._meta.exclude:
413 exclude.add(f.name)
414
415 # Exclude fields that failed form validation. There's no need for
416 # the model fields to validate them as well.
417 elif field in self._errors:
418 exclude.add(f.name)
419
420 # Exclude empty fields that are not required by the form, if the
421 # underlying model field is required. This keeps the model field
422 # from raising a required error. Note: don't exclude the field from
423 # validation if the model field allows blanks. If it does, the blank
424 # value may be included in a unique check, so cannot be excluded
425 # from validation.
426 else:
427 form_field = self.fields[field]
428 field_value = self.cleaned_data.get(field)
429 if (
430 not f.blank
431 and not form_field.required
432 and field_value in form_field.empty_values
433 ):
434 exclude.add(f.name)
435 return exclude
436
437 def clean(self):
438 self._validate_unique = True
439 return self.cleaned_data
440
441 def _update_errors(self, errors):
442 # Override any validation error messages defined at the model level
443 # with those defined at the form level.
444 opts = self._meta
445
446 # Allow the model generated by construct_instance() to raise
447 # ValidationError and have them handled in the same way as others.
448 if hasattr(errors, "error_dict"):
449 error_dict = errors.error_dict
450 else:
451 error_dict = {NON_FIELD_ERRORS: errors}
452
453 for field, messages in error_dict.items():
454 if (
455 field == NON_FIELD_ERRORS
456 and opts.error_messages
457 and NON_FIELD_ERRORS in opts.error_messages
458 ):
459 error_messages = opts.error_messages[NON_FIELD_ERRORS]
460 elif field in self.fields:
461 error_messages = self.fields[field].error_messages
462 else:
463 continue
464
465 for message in messages:
466 if (
467 isinstance(message, ValidationError)
468 and message.code in error_messages
469 ):
470 message.message = error_messages[message.code]
471
472 self.add_error(None, errors)
473
474 def _post_clean(self):
475 opts = self._meta
476
477 exclude = self._get_validation_exclusions()
478
479 # Foreign Keys being used to represent inline relationships
480 # are excluded from basic field value validation. This is for two
481 # reasons: firstly, the value may not be supplied (#12507; the
482 # case of providing new values to the admin); secondly the
483 # object being referred to may not yet fully exist (#12749).
484 # However, these fields *must* be included in uniqueness checks,
485 # so this can't be part of _get_validation_exclusions().
486 for name, field in self.fields.items():
487 if isinstance(field, InlineForeignKeyField):
488 exclude.add(name)
489
490 try:
491 self.instance = construct_instance(
492 self, self.instance, opts.fields, opts.exclude
493 )
494 except ValidationError as e:
495 self._update_errors(e)
496
497 try:
498 self.instance.full_clean(exclude=exclude, validate_unique=False)
499 except ValidationError as e:
500 self._update_errors(e)
501
502 # Validate uniqueness if needed.
503 if self._validate_unique:
504 self.validate_unique()
505
506 def validate_unique(self):
507 """
508 Call the instance's validate_unique() method and update the form's
509 validation errors if any were raised.
510 """
511 exclude = self._get_validation_exclusions()
512 try:
513 self.instance.validate_unique(exclude=exclude)
514 except ValidationError as e:
515 self._update_errors(e)
516
517 def _save_m2m(self):
518 """
519 Save the many-to-many fields and generic relations for this form.
520 """
521 cleaned_data = self.cleaned_data
522 exclude = self._meta.exclude
523 fields = self._meta.fields
524 opts = self.instance._meta
525 # Note that for historical reasons we want to include also
526 # private_fields here. (GenericRelation was previously a fake
527 # m2m field).
528 for f in chain(opts.many_to_many, opts.private_fields):
529 if not hasattr(f, "save_form_data"):
530 continue
531 if fields and f.name not in fields:
532 continue
533 if exclude and f.name in exclude:
534 continue
535 if f.name in cleaned_data:
536 f.save_form_data(self.instance, cleaned_data[f.name])
537
538 def save(self, commit=True):
539 """
540 Save this form's self.instance object if commit=True. Otherwise, add
541 a save_m2m() method to the form which can be called after the instance
542 is saved manually at a later time. Return the model instance.
543 """
544 if self.errors:
545 raise ValueError(
546 "The %s could not be %s because the data didn't validate."
547 % (
548 self.instance._meta.object_name,
549 "created" if self.instance._state.adding else "changed",
550 )
551 )
552 if commit:
553 # If committing, save the instance and the m2m data immediately.
554 self.instance.save()
555 self._save_m2m()
556 else:
557 # If not committing, add a method to the form to allow deferred
558 # saving of m2m data.
559 self.save_m2m = self._save_m2m
560 return self.instance
561
562 save.alters_data = True
563
564
565class ModelForm(BaseModelForm, metaclass=ModelFormMetaclass):
566 pass
567
568
569def modelform_factory(
570 model,
571 form=ModelForm,
572 fields=None,
573 exclude=None,
574 formfield_callback=None,
575 widgets=None,
576 localized_fields=None,
577 labels=None,
578 help_texts=None,
579 error_messages=None,
580 field_classes=None,
581):
582 """
583 Return a ModelForm containing form fields for the given model. You can
584 optionally pass a `form` argument to use as a starting point for
585 constructing the ModelForm.
586
587 ``fields`` is an optional list of field names. If provided, include only
588 the named fields in the returned fields. If omitted or '__all__', use all
589 fields.
590
591 ``exclude`` is an optional list of field names. If provided, exclude the
592 named fields from the returned fields, even if they are listed in the
593 ``fields`` argument.
594
595 ``widgets`` is a dictionary of model field names mapped to a widget.
596
597 ``localized_fields`` is a list of names of fields which should be localized.
598
599 ``formfield_callback`` is a callable that takes a model field and returns
600 a form field.
601
602 ``labels`` is a dictionary of model field names mapped to a label.
603
604 ``help_texts`` is a dictionary of model field names mapped to a help text.
605
606 ``error_messages`` is a dictionary of model field names mapped to a
607 dictionary of error messages.
608
609 ``field_classes`` is a dictionary of model field names mapped to a form
610 field class.
611 """
612 # Create the inner Meta class. FIXME: ideally, we should be able to
613 # construct a ModelForm without creating and passing in a temporary
614 # inner class.
615
616 # Build up a list of attributes that the Meta object will have.
617 attrs = {"model": model}
618 if fields is not None:
619 attrs["fields"] = fields
620 if exclude is not None:
621 attrs["exclude"] = exclude
622 if widgets is not None:
623 attrs["widgets"] = widgets
624 if localized_fields is not None:
625 attrs["localized_fields"] = localized_fields
626 if labels is not None:
627 attrs["labels"] = labels
628 if help_texts is not None:
629 attrs["help_texts"] = help_texts
630 if error_messages is not None:
631 attrs["error_messages"] = error_messages
632 if field_classes is not None:
633 attrs["field_classes"] = field_classes
634
635 # If parent form class already has an inner Meta, the Meta we're
636 # creating needs to inherit from the parent's inner meta.
637 bases = (form.Meta,) if hasattr(form, "Meta") else ()
638 Meta = type("Meta", bases, attrs)
639 if formfield_callback:
640 Meta.formfield_callback = staticmethod(formfield_callback)
641 # Give this new form class a reasonable name.
642 class_name = model.__name__ + "Form"
643
644 # Class attributes for the new form class.
645 form_class_attrs = {"Meta": Meta}
646
647 if getattr(Meta, "fields", None) is None and getattr(Meta, "exclude", None) is None:
648 raise ImproperlyConfigured(
649 "Calling modelform_factory without defining 'fields' or "
650 "'exclude' explicitly is prohibited."
651 )
652
653 # Instantiate type(form) in order to use the same metaclass as form.
654 return type(form)(class_name, (form,), form_class_attrs)
655
656
657# ModelFormSets ##############################################################
658
659
660class BaseModelFormSet(BaseFormSet, AltersData):
661 """
662 A ``FormSet`` for editing a queryset and/or adding new objects to it.
663 """
664
665 model = None
666 edit_only = False
667
668 # Set of fields that must be unique among forms of this set.
669 unique_fields = set()
670
671 def __init__(
672 self,
673 data=None,
674 files=None,
675 auto_id="id_%s",
676 prefix=None,
677 queryset=None,
678 *,
679 initial=None,
680 **kwargs,
681 ):
682 self.queryset = queryset
683 self.initial_extra = initial
684 super().__init__(
685 **{
686 "data": data,
687 "files": files,
688 "auto_id": auto_id,
689 "prefix": prefix,
690 **kwargs,
691 }
692 )
693
694 def initial_form_count(self):
695 """Return the number of forms that are required in this FormSet."""
696 if not self.is_bound:
697 return len(self.get_queryset())
698 return super().initial_form_count()
699
700 def _existing_object(self, pk):
701 if not hasattr(self, "_object_dict"):
702 self._object_dict = {o.pk: o for o in self.get_queryset()}
703 return self._object_dict.get(pk)
704
705 def _get_to_python(self, field):
706 """
707 If the field is a related field, fetch the concrete field's (that
708 is, the ultimate pointed-to field's) to_python.
709 """
710 while field.remote_field is not None:
711 field = field.remote_field.get_related_field()
712 return field.to_python
713
714 def _construct_form(self, i, **kwargs):
715 pk_required = i < self.initial_form_count()
716 if pk_required:
717 if self.is_bound:
718 pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
719 try:
720 pk = self.data[pk_key]
721 except KeyError:
722 # The primary key is missing. The user may have tampered
723 # with POST data.
724 pass
725 else:
726 to_python = self._get_to_python(self.model._meta.pk)
727 try:
728 pk = to_python(pk)
729 except ValidationError:
730 # The primary key exists but is an invalid value. The
731 # user may have tampered with POST data.
732 pass
733 else:
734 kwargs["instance"] = self._existing_object(pk)
735 else:
736 kwargs["instance"] = self.get_queryset()[i]
737 elif self.initial_extra:
738 # Set initial values for extra forms
739 try:
740 kwargs["initial"] = self.initial_extra[i - self.initial_form_count()]
741 except IndexError:
742 pass
743 form = super()._construct_form(i, **kwargs)
744 if pk_required:
745 form.fields[self.model._meta.pk.name].required = True
746 return form
747
748 def get_queryset(self):
749 if not hasattr(self, "_queryset"):
750 if self.queryset is not None:
751 qs = self.queryset
752 else:
753 qs = self.model._default_manager.get_queryset()
754
755 # If the queryset isn't already ordered we need to add an
756 # artificial ordering here to make sure that all formsets
757 # constructed from this queryset have the same form order.
758 if not qs.ordered:
759 qs = qs.order_by(self.model._meta.pk.name)
760
761 # Removed queryset limiting here. As per discussion re: #13023
762 # on django-dev, max_num should not prevent existing
763 # related objects/inlines from being displayed.
764 self._queryset = qs
765 return self._queryset
766
767 def save_new(self, form, commit=True):
768 """Save and return a new model instance for the given form."""
769 return form.save(commit=commit)
770
771 def save_existing(self, form, obj, commit=True):
772 """Save and return an existing model instance for the given form."""
773 return form.save(commit=commit)
774
775 def delete_existing(self, obj, commit=True):
776 """Deletes an existing model instance."""
777 if commit:
778 obj.delete()
779
780 def save(self, commit=True):
781 """
782 Save model instances for every form, adding and changing instances
783 as necessary, and return the list of instances.
784 """
785 if not commit:
786 self.saved_forms = []
787
788 def save_m2m():
789 for form in self.saved_forms:
790 form.save_m2m()
791
792 self.save_m2m = save_m2m
793 if self.edit_only:
794 return self.save_existing_objects(commit)
795 else:
796 return self.save_existing_objects(commit) + self.save_new_objects(commit)
797
798 save.alters_data = True
799
800 def clean(self):
801 self.validate_unique()
802
803 def validate_unique(self):
804 # Collect unique_checks and date_checks to run from all the forms.
805 all_unique_checks = set()
806 all_date_checks = set()
807 forms_to_delete = self.deleted_forms
808 valid_forms = [
809 form
810 for form in self.forms
811 if form.is_valid() and form not in forms_to_delete
812 ]
813 for form in valid_forms:
814 exclude = form._get_validation_exclusions()
815 unique_checks, date_checks = form.instance._get_unique_checks(
816 exclude=exclude,
817 include_meta_constraints=True,
818 )
819 all_unique_checks.update(unique_checks)
820 all_date_checks.update(date_checks)
821
822 errors = []
823 # Do each of the unique checks (unique and unique_together)
824 for uclass, unique_check in all_unique_checks:
825 seen_data = set()
826 for form in valid_forms:
827 # Get the data for the set of fields that must be unique among
828 # the forms.
829 row_data = (
830 field if field in self.unique_fields else form.cleaned_data[field]
831 for field in unique_check
832 if field in form.cleaned_data
833 )
834 # Reduce Model instances to their primary key values
835 row_data = tuple(
836 (
837 d._get_pk_val()
838 if hasattr(d, "_get_pk_val")
839 # Prevent "unhashable type" errors later on.
840 else make_hashable(d)
841 )
842 for d in row_data
843 )
844 if row_data and None not in row_data:
845 # if we've already seen it then we have a uniqueness failure
846 if row_data in seen_data:
847 # poke error messages into the right places and mark
848 # the form as invalid
849 errors.append(self.get_unique_error_message(unique_check))
850 form._errors[NON_FIELD_ERRORS] = self.error_class(
851 [self.get_form_error()],
852 renderer=self.renderer,
853 )
854 # Remove the data from the cleaned_data dict since it
855 # was invalid.
856 for field in unique_check:
857 if field in form.cleaned_data:
858 del form.cleaned_data[field]
859 # mark the data as seen
860 seen_data.add(row_data)
861 # iterate over each of the date checks now
862 for date_check in all_date_checks:
863 seen_data = set()
864 uclass, lookup, field, unique_for = date_check
865 for form in valid_forms:
866 # see if we have data for both fields
867 if (
868 form.cleaned_data
869 and form.cleaned_data[field] is not None
870 and form.cleaned_data[unique_for] is not None
871 ):
872 # if it's a date lookup we need to get the data for all the fields
873 if lookup == "date":
874 date = form.cleaned_data[unique_for]
875 date_data = (date.year, date.month, date.day)
876 # otherwise it's just the attribute on the date/datetime
877 # object
878 else:
879 date_data = (getattr(form.cleaned_data[unique_for], lookup),)
880 data = (form.cleaned_data[field],) + date_data
881 # if we've already seen it then we have a uniqueness failure
882 if data in seen_data:
883 # poke error messages into the right places and mark
884 # the form as invalid
885 errors.append(self.get_date_error_message(date_check))
886 form._errors[NON_FIELD_ERRORS] = self.error_class(
887 [self.get_form_error()],
888 renderer=self.renderer,
889 )
890 # Remove the data from the cleaned_data dict since it
891 # was invalid.
892 del form.cleaned_data[field]
893 # mark the data as seen
894 seen_data.add(data)
895
896 if errors:
897 raise ValidationError(errors)
898
899 def get_unique_error_message(self, unique_check):
900 if len(unique_check) == 1:
901 return gettext("Please correct the duplicate data for %(field)s.") % {
902 "field": unique_check[0],
903 }
904 else:
905 return gettext(
906 "Please correct the duplicate data for %(field)s, which must be unique."
907 ) % {
908 "field": get_text_list(unique_check, _("and")),
909 }
910
911 def get_date_error_message(self, date_check):
912 return gettext(
913 "Please correct the duplicate data for %(field_name)s "
914 "which must be unique for the %(lookup)s in %(date_field)s."
915 ) % {
916 "field_name": date_check[2],
917 "date_field": date_check[3],
918 "lookup": str(date_check[1]),
919 }
920
921 def get_form_error(self):
922 return gettext("Please correct the duplicate values below.")
923
924 def save_existing_objects(self, commit=True):
925 self.changed_objects = []
926 self.deleted_objects = []
927 if not self.initial_forms:
928 return []
929
930 saved_instances = []
931 forms_to_delete = self.deleted_forms
932 for form in self.initial_forms:
933 obj = form.instance
934 # If the pk is None, it means either:
935 # 1. The object is an unexpected empty model, created by invalid
936 # POST data such as an object outside the formset's queryset.
937 # 2. The object was already deleted from the database.
938 if not obj._is_pk_set():
939 continue
940 if form in forms_to_delete:
941 self.deleted_objects.append(obj)
942 self.delete_existing(obj, commit=commit)
943 elif form.has_changed():
944 self.changed_objects.append((obj, form.changed_data))
945 saved_instances.append(self.save_existing(form, obj, commit=commit))
946 if not commit:
947 self.saved_forms.append(form)
948 return saved_instances
949
950 def save_new_objects(self, commit=True):
951 self.new_objects = []
952 for form in self.extra_forms:
953 if not form.has_changed():
954 continue
955 # If someone has marked an add form for deletion, don't save the
956 # object.
957 if self.can_delete and self._should_delete_form(form):
958 continue
959 self.new_objects.append(self.save_new(form, commit=commit))
960 if not commit:
961 self.saved_forms.append(form)
962 return self.new_objects
963
964 def add_fields(self, form, index):
965 """Add a hidden field for the object's primary key."""
966 from django.db.models import AutoField, ForeignKey, OneToOneField
967
968 self._pk_field = pk = self.model._meta.pk
969 # If a pk isn't editable, then it won't be on the form, so we need to
970 # add it here so we can tell which object is which when we get the
971 # data back. Generally, pk.editable should be false, but for some
972 # reason, auto_created pk fields and AutoField's editable attribute is
973 # True, so check for that as well.
974
975 def pk_is_not_editable(pk):
976 return (
977 (not pk.editable)
978 or (pk.auto_created or isinstance(pk, AutoField))
979 or (
980 pk.remote_field
981 and pk.remote_field.parent_link
982 and pk_is_not_editable(pk.remote_field.model._meta.pk)
983 )
984 )
985
986 if pk_is_not_editable(pk) or pk.name not in form.fields:
987 if form.is_bound:
988 # If we're adding the related instance, ignore its primary key
989 # as it could be an auto-generated default which isn't actually
990 # in the database.
991 pk_value = None if form.instance._state.adding else form.instance.pk
992 else:
993 try:
994 if index is not None:
995 pk_value = self.get_queryset()[index].pk
996 else:
997 pk_value = None
998 except IndexError:
999 pk_value = None
1000 if isinstance(pk, (ForeignKey, OneToOneField)):
1001 qs = pk.remote_field.model._default_manager.get_queryset()
1002 else:
1003 qs = self.model._default_manager.get_queryset()
1004 qs = qs.using(form.instance._state.db)
1005 if form._meta.widgets:
1006 widget = form._meta.widgets.get(self._pk_field.name, HiddenInput)
1007 else:
1008 widget = HiddenInput
1009 form.fields[self._pk_field.name] = ModelChoiceField(
1010 qs, initial=pk_value, required=False, widget=widget
1011 )
1012 super().add_fields(form, index)
1013
1014
1015def modelformset_factory(
1016 model,
1017 form=ModelForm,
1018 formfield_callback=None,
1019 formset=BaseModelFormSet,
1020 extra=1,
1021 can_delete=False,
1022 can_order=False,
1023 max_num=None,
1024 fields=None,
1025 exclude=None,
1026 widgets=None,
1027 validate_max=False,
1028 localized_fields=None,
1029 labels=None,
1030 help_texts=None,
1031 error_messages=None,
1032 min_num=None,
1033 validate_min=False,
1034 field_classes=None,
1035 absolute_max=None,
1036 can_delete_extra=True,
1037 renderer=None,
1038 edit_only=False,
1039):
1040 """Return a FormSet class for the given Django model class."""
1041 meta = getattr(form, "Meta", None)
1042 if (
1043 getattr(meta, "fields", fields) is None
1044 and getattr(meta, "exclude", exclude) is None
1045 ):
1046 raise ImproperlyConfigured(
1047 "Calling modelformset_factory without defining 'fields' or "
1048 "'exclude' explicitly is prohibited."
1049 )
1050
1051 form = modelform_factory(
1052 model,
1053 form=form,
1054 fields=fields,
1055 exclude=exclude,
1056 formfield_callback=formfield_callback,
1057 widgets=widgets,
1058 localized_fields=localized_fields,
1059 labels=labels,
1060 help_texts=help_texts,
1061 error_messages=error_messages,
1062 field_classes=field_classes,
1063 )
1064 FormSet = formset_factory(
1065 form,
1066 formset,
1067 extra=extra,
1068 min_num=min_num,
1069 max_num=max_num,
1070 can_order=can_order,
1071 can_delete=can_delete,
1072 validate_min=validate_min,
1073 validate_max=validate_max,
1074 absolute_max=absolute_max,
1075 can_delete_extra=can_delete_extra,
1076 renderer=renderer,
1077 )
1078 FormSet.model = model
1079 FormSet.edit_only = edit_only
1080 return FormSet
1081
1082
1083# InlineFormSets #############################################################
1084
1085
1086class BaseInlineFormSet(BaseModelFormSet):
1087 """A formset for child objects related to a parent."""
1088
1089 def __init__(
1090 self,
1091 data=None,
1092 files=None,
1093 instance=None,
1094 save_as_new=False,
1095 prefix=None,
1096 queryset=None,
1097 **kwargs,
1098 ):
1099 if instance is None:
1100 self.instance = self.fk.remote_field.model()
1101 else:
1102 self.instance = instance
1103 self.save_as_new = save_as_new
1104 if queryset is None:
1105 queryset = self.model._default_manager
1106 if self.instance._is_pk_set():
1107 qs = queryset.filter(**{self.fk.name: self.instance})
1108 else:
1109 qs = queryset.none()
1110 self.unique_fields = {self.fk.name}
1111 super().__init__(data, files, prefix=prefix, queryset=qs, **kwargs)
1112
1113 # Add the generated field to form._meta.fields if it's defined to make
1114 # sure validation isn't skipped on that field.
1115 if self.form._meta.fields and self.fk.name not in self.form._meta.fields:
1116 if isinstance(self.form._meta.fields, tuple):
1117 self.form._meta.fields = list(self.form._meta.fields)
1118 self.form._meta.fields.append(self.fk.name)
1119
1120 def initial_form_count(self):
1121 if self.save_as_new:
1122 return 0
1123 return super().initial_form_count()
1124
1125 def _construct_form(self, i, **kwargs):
1126 form = super()._construct_form(i, **kwargs)
1127 if self.save_as_new:
1128 mutable = getattr(form.data, "_mutable", None)
1129 # Allow modifying an immutable QueryDict.
1130 if mutable is not None:
1131 form.data._mutable = True
1132 # Remove the primary key from the form's data, we are only
1133 # creating new instances
1134 form.data[form.add_prefix(self._pk_field.name)] = None
1135 # Remove the foreign key from the form's data
1136 form.data[form.add_prefix(self.fk.name)] = None
1137 if mutable is not None:
1138 form.data._mutable = mutable
1139
1140 # Set the fk value here so that the form can do its validation.
1141 fk_value = self.instance.pk
1142 if self.fk.remote_field.field_name != self.fk.remote_field.model._meta.pk.name:
1143 fk_value = getattr(self.instance, self.fk.remote_field.field_name)
1144 fk_value = getattr(fk_value, "pk", fk_value)
1145 setattr(form.instance, self.fk.attname, fk_value)
1146 return form
1147
1148 @classmethod
1149 def get_default_prefix(cls):
1150 return cls.fk.remote_field.get_accessor_name(model=cls.model).replace("+", "")
1151
1152 def save_new(self, form, commit=True):
1153 # Ensure the latest copy of the related instance is present on each
1154 # form (it may have been saved after the formset was originally
1155 # instantiated).
1156 setattr(form.instance, self.fk.name, self.instance)
1157 return super().save_new(form, commit=commit)
1158
1159 def add_fields(self, form, index):
1160 super().add_fields(form, index)
1161 if self._pk_field == self.fk:
1162 name = self._pk_field.name
1163 kwargs = {"pk_field": True}
1164 else:
1165 # The foreign key field might not be on the form, so we poke at the
1166 # Model field to get the label, since we need that for error messages.
1167 name = self.fk.name
1168 kwargs = {
1169 "label": getattr(
1170 form.fields.get(name), "label", capfirst(self.fk.verbose_name)
1171 )
1172 }
1173
1174 # The InlineForeignKeyField assumes that the foreign key relation is
1175 # based on the parent model's pk. If this isn't the case, set to_field
1176 # to correctly resolve the initial form value.
1177 if self.fk.remote_field.field_name != self.fk.remote_field.model._meta.pk.name:
1178 kwargs["to_field"] = self.fk.remote_field.field_name
1179
1180 # If we're adding a new object, ignore a parent's auto-generated key
1181 # as it will be regenerated on the save request.
1182 if self.instance._state.adding:
1183 if kwargs.get("to_field") is not None:
1184 to_field = self.instance._meta.get_field(kwargs["to_field"])
1185 else:
1186 to_field = self.instance._meta.pk
1187
1188 if to_field.has_default() and (
1189 # Don't ignore a parent's auto-generated key if it's not the
1190 # parent model's pk and form data is provided.
1191 to_field.attname == self.fk.remote_field.model._meta.pk.name
1192 or not form.data
1193 ):
1194 setattr(self.instance, to_field.attname, None)
1195
1196 form.fields[name] = InlineForeignKeyField(self.instance, **kwargs)
1197
1198 def get_unique_error_message(self, unique_check):
1199 unique_check = [field for field in unique_check if field != self.fk.name]
1200 return super().get_unique_error_message(unique_check)
1201
1202
1203def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
1204 """
1205 Find and return the ForeignKey from model to parent if there is one
1206 (return None if can_fail is True and no such field exists). If fk_name is
1207 provided, assume it is the name of the ForeignKey field. Unless can_fail is
1208 True, raise an exception if there isn't a ForeignKey from model to
1209 parent_model.
1210 """
1211 # avoid circular import
1212 from django.db.models import ForeignKey
1213
1214 opts = model._meta
1215 if fk_name:
1216 fks_to_parent = [f for f in opts.fields if f.name == fk_name]
1217 if len(fks_to_parent) == 1:
1218 fk = fks_to_parent[0]
1219 all_parents = (*parent_model._meta.all_parents, parent_model)
1220 if (
1221 not isinstance(fk, ForeignKey)
1222 or (
1223 # ForeignKey to proxy models.
1224 fk.remote_field.model._meta.proxy
1225 and fk.remote_field.model._meta.proxy_for_model not in all_parents
1226 )
1227 or (
1228 # ForeignKey to concrete models.
1229 not fk.remote_field.model._meta.proxy
1230 and fk.remote_field.model != parent_model
1231 and fk.remote_field.model not in all_parents
1232 )
1233 ):
1234 raise ValueError(
1235 "fk_name '%s' is not a ForeignKey to '%s'."
1236 % (fk_name, parent_model._meta.label)
1237 )
1238 elif not fks_to_parent:
1239 raise ValueError(
1240 "'%s' has no field named '%s'." % (model._meta.label, fk_name)
1241 )
1242 else:
1243 # Try to discover what the ForeignKey from model to parent_model is
1244 all_parents = (*parent_model._meta.all_parents, parent_model)
1245 fks_to_parent = [
1246 f
1247 for f in opts.fields
1248 if isinstance(f, ForeignKey)
1249 and (
1250 f.remote_field.model == parent_model
1251 or f.remote_field.model in all_parents
1252 or (
1253 f.remote_field.model._meta.proxy
1254 and f.remote_field.model._meta.proxy_for_model in all_parents
1255 )
1256 )
1257 ]
1258 if len(fks_to_parent) == 1:
1259 fk = fks_to_parent[0]
1260 elif not fks_to_parent:
1261 if can_fail:
1262 return
1263 raise ValueError(
1264 "'%s' has no ForeignKey to '%s'."
1265 % (
1266 model._meta.label,
1267 parent_model._meta.label,
1268 )
1269 )
1270 else:
1271 raise ValueError(
1272 "'%s' has more than one ForeignKey to '%s'. You must specify "
1273 "a 'fk_name' attribute."
1274 % (
1275 model._meta.label,
1276 parent_model._meta.label,
1277 )
1278 )
1279 return fk
1280
1281
1282def inlineformset_factory(
1283 parent_model,
1284 model,
1285 form=ModelForm,
1286 formset=BaseInlineFormSet,
1287 fk_name=None,
1288 fields=None,
1289 exclude=None,
1290 extra=3,
1291 can_order=False,
1292 can_delete=True,
1293 max_num=None,
1294 formfield_callback=None,
1295 widgets=None,
1296 validate_max=False,
1297 localized_fields=None,
1298 labels=None,
1299 help_texts=None,
1300 error_messages=None,
1301 min_num=None,
1302 validate_min=False,
1303 field_classes=None,
1304 absolute_max=None,
1305 can_delete_extra=True,
1306 renderer=None,
1307 edit_only=False,
1308):
1309 """
1310 Return an ``InlineFormSet`` for the given kwargs.
1311
1312 ``fk_name`` must be provided if ``model`` has more than one ``ForeignKey``
1313 to ``parent_model``.
1314 """
1315 fk = _get_foreign_key(parent_model, model, fk_name=fk_name)
1316 # enforce a max_num=1 when the foreign key to the parent model is unique.
1317 if fk.unique:
1318 max_num = 1
1319 kwargs = {
1320 "form": form,
1321 "formfield_callback": formfield_callback,
1322 "formset": formset,
1323 "extra": extra,
1324 "can_delete": can_delete,
1325 "can_order": can_order,
1326 "fields": fields,
1327 "exclude": exclude,
1328 "min_num": min_num,
1329 "max_num": max_num,
1330 "widgets": widgets,
1331 "validate_min": validate_min,
1332 "validate_max": validate_max,
1333 "localized_fields": localized_fields,
1334 "labels": labels,
1335 "help_texts": help_texts,
1336 "error_messages": error_messages,
1337 "field_classes": field_classes,
1338 "absolute_max": absolute_max,
1339 "can_delete_extra": can_delete_extra,
1340 "renderer": renderer,
1341 "edit_only": edit_only,
1342 }
1343 FormSet = modelformset_factory(model, **kwargs)
1344 FormSet.fk = fk
1345 return FormSet
1346
1347
1348# Fields #####################################################################
1349
1350
1351class InlineForeignKeyField(Field):
1352 """
1353 A basic integer field that deals with validating the given value to a
1354 given parent instance in an inline.
1355 """
1356
1357 widget = HiddenInput
1358 default_error_messages = {
1359 "invalid_choice": _("The inline value did not match the parent instance."),
1360 }
1361
1362 def __init__(self, parent_instance, *args, pk_field=False, to_field=None, **kwargs):
1363 self.parent_instance = parent_instance
1364 self.pk_field = pk_field
1365 self.to_field = to_field
1366 if self.parent_instance is not None:
1367 if self.to_field:
1368 kwargs["initial"] = getattr(self.parent_instance, self.to_field)
1369 else:
1370 kwargs["initial"] = self.parent_instance.pk
1371 kwargs["required"] = False
1372 super().__init__(*args, **kwargs)
1373
1374 def clean(self, value):
1375 if value in self.empty_values:
1376 if self.pk_field:
1377 return None
1378 # if there is no value act as we did before.
1379 return self.parent_instance
1380 # ensure the we compare the values as equal types.
1381 if self.to_field:
1382 orig = getattr(self.parent_instance, self.to_field)
1383 else:
1384 orig = self.parent_instance.pk
1385 if str(value) != str(orig):
1386 raise ValidationError(
1387 self.error_messages["invalid_choice"], code="invalid_choice"
1388 )
1389 return self.parent_instance
1390
1391 def has_changed(self, initial, data):
1392 return False
1393
1394
1395class ModelChoiceIteratorValue:
1396 def __init__(self, value, instance):
1397 self.value = value
1398 self.instance = instance
1399
1400 def __str__(self):
1401 return str(self.value)
1402
1403 def __hash__(self):
1404 return hash(self.value)
1405
1406 def __eq__(self, other):
1407 if isinstance(other, ModelChoiceIteratorValue):
1408 other = other.value
1409 return self.value == other
1410
1411
1412class ModelChoiceIterator(BaseChoiceIterator):
1413 def __init__(self, field):
1414 self.field = field
1415 self.queryset = field.queryset
1416
1417 def __iter__(self):
1418 if self.field.empty_label is not None:
1419 yield ("", self.field.empty_label)
1420 queryset = self.queryset
1421 # Can't use iterator() when queryset uses prefetch_related()
1422 if not queryset._prefetch_related_lookups:
1423 queryset = queryset.iterator()
1424 for obj in queryset:
1425 yield self.choice(obj)
1426
1427 def __len__(self):
1428 # count() adds a query but uses less memory since the QuerySet results
1429 # won't be cached. In most cases, the choices will only be iterated on,
1430 # and __len__() won't be called.
1431 return self.queryset.count() + (1 if self.field.empty_label is not None else 0)
1432
1433 def __bool__(self):
1434 return self.field.empty_label is not None or self.queryset.exists()
1435
1436 def choice(self, obj):
1437 return (
1438 ModelChoiceIteratorValue(self.field.prepare_value(obj), obj),
1439 self.field.label_from_instance(obj),
1440 )
1441
1442
1443class ModelChoiceField(ChoiceField):
1444 """A ChoiceField whose choices are a model QuerySet."""
1445
1446 # This class is a subclass of ChoiceField for purity, but it doesn't
1447 # actually use any of ChoiceField's implementation.
1448 default_error_messages = {
1449 "invalid_choice": _(
1450 "Select a valid choice. That choice is not one of the available choices."
1451 ),
1452 }
1453 iterator = ModelChoiceIterator
1454
1455 def __init__(
1456 self,
1457 queryset,
1458 *,
1459 empty_label="---------",
1460 required=True,
1461 widget=None,
1462 label=None,
1463 initial=None,
1464 help_text="",
1465 to_field_name=None,
1466 limit_choices_to=None,
1467 blank=False,
1468 **kwargs,
1469 ):
1470 # Call Field instead of ChoiceField __init__() because we don't need
1471 # ChoiceField.__init__().
1472 Field.__init__(
1473 self,
1474 required=required,
1475 widget=widget,
1476 label=label,
1477 initial=initial,
1478 help_text=help_text,
1479 **kwargs,
1480 )
1481 if (required and initial is not None) or (
1482 isinstance(self.widget, RadioSelect) and not blank
1483 ):
1484 self.empty_label = None
1485 else:
1486 self.empty_label = empty_label
1487 self.queryset = queryset
1488 self.limit_choices_to = limit_choices_to # limit the queryset later.
1489 self.to_field_name = to_field_name
1490
1491 def validate_no_null_characters(self, value):
1492 non_null_character_validator = ProhibitNullCharactersValidator()
1493 return non_null_character_validator(value)
1494
1495 def get_limit_choices_to(self):
1496 """
1497 Return ``limit_choices_to`` for this form field.
1498
1499 If it is a callable, invoke it and return the result.
1500 """
1501 if callable(self.limit_choices_to):
1502 return self.limit_choices_to()
1503 return self.limit_choices_to
1504
1505 def __deepcopy__(self, memo):
1506 result = super(ChoiceField, self).__deepcopy__(memo)
1507 # Need to force a new ModelChoiceIterator to be created, bug #11183
1508 if self.queryset is not None:
1509 result.queryset = self.queryset.all()
1510 return result
1511
1512 def _get_queryset(self):
1513 return self._queryset
1514
1515 def _set_queryset(self, queryset):
1516 self._queryset = None if queryset is None else queryset.all()
1517 self.widget.choices = self.choices
1518
1519 queryset = property(_get_queryset, _set_queryset)
1520
1521 # this method will be used to create object labels by the QuerySetIterator.
1522 # Override it to customize the label.
1523 def label_from_instance(self, obj):
1524 """
1525 Convert objects into strings and generate the labels for the choices
1526 presented by this object. Subclasses can override this method to
1527 customize the display of the choices.
1528 """
1529 return str(obj)
1530
1531 def _get_choices(self):
1532 # If self._choices is set, then somebody must have manually set
1533 # the property self.choices. In this case, just return self._choices.
1534 if hasattr(self, "_choices"):
1535 return self._choices
1536
1537 # Otherwise, execute the QuerySet in self.queryset to determine the
1538 # choices dynamically. Return a fresh ModelChoiceIterator that has not been
1539 # consumed. Note that we're instantiating a new ModelChoiceIterator *each*
1540 # time _get_choices() is called (and, thus, each time self.choices is
1541 # accessed) so that we can ensure the QuerySet has not been consumed. This
1542 # construct might look complicated but it allows for lazy evaluation of
1543 # the queryset.
1544 return self.iterator(self)
1545
1546 choices = property(_get_choices, ChoiceField.choices.fset)
1547
1548 def prepare_value(self, value):
1549 if hasattr(value, "_meta"):
1550 if self.to_field_name:
1551 return value.serializable_value(self.to_field_name)
1552 else:
1553 return value.pk
1554 return super().prepare_value(value)
1555
1556 def to_python(self, value):
1557 if value in self.empty_values:
1558 return None
1559 self.validate_no_null_characters(value)
1560 try:
1561 key = self.to_field_name or "pk"
1562 if isinstance(value, self.queryset.model):
1563 value = getattr(value, key)
1564 value = self.queryset.get(**{key: value})
1565 except (ValueError, TypeError, self.queryset.model.DoesNotExist):
1566 raise ValidationError(
1567 self.error_messages["invalid_choice"],
1568 code="invalid_choice",
1569 params={"value": value},
1570 )
1571 return value
1572
1573 def validate(self, value):
1574 return Field.validate(self, value)
1575
1576 def has_changed(self, initial, data):
1577 if self.disabled:
1578 return False
1579 initial_value = initial if initial is not None else ""
1580 data_value = data if data is not None else ""
1581 return str(self.prepare_value(initial_value)) != str(data_value)
1582
1583
1584class ModelMultipleChoiceField(ModelChoiceField):
1585 """A MultipleChoiceField whose choices are a model QuerySet."""
1586
1587 widget = SelectMultiple
1588 hidden_widget = MultipleHiddenInput
1589 default_error_messages = {
1590 "invalid_list": _("Enter a list of values."),
1591 "invalid_choice": _(
1592 "Select a valid choice. %(value)s is not one of the available choices."
1593 ),
1594 "invalid_pk_value": _("“%(pk)s” is not a valid value."),
1595 }
1596
1597 def __init__(self, queryset, **kwargs):
1598 super().__init__(queryset, empty_label=None, **kwargs)
1599
1600 def to_python(self, value):
1601 if not value:
1602 return []
1603 return list(self._check_values(value))
1604
1605 def clean(self, value):
1606 value = self.prepare_value(value)
1607 if self.required and not value:
1608 raise ValidationError(self.error_messages["required"], code="required")
1609 elif not self.required and not value:
1610 return self.queryset.none()
1611 if not isinstance(value, (list, tuple)):
1612 raise ValidationError(
1613 self.error_messages["invalid_list"],
1614 code="invalid_list",
1615 )
1616 qs = self._check_values(value)
1617 # Since this overrides the inherited ModelChoiceField.clean
1618 # we run custom validators here
1619 self.run_validators(value)
1620 return qs
1621
1622 def _check_values(self, value):
1623 """
1624 Given a list of possible PK values, return a QuerySet of the
1625 corresponding objects. Raise a ValidationError if a given value is
1626 invalid (not a valid PK, not in the queryset, etc.)
1627 """
1628 key = self.to_field_name or "pk"
1629 # deduplicate given values to avoid creating many querysets or
1630 # requiring the database backend deduplicate efficiently.
1631 try:
1632 value = frozenset(value)
1633 except TypeError:
1634 # list of lists isn't hashable, for example
1635 raise ValidationError(
1636 self.error_messages["invalid_list"],
1637 code="invalid_list",
1638 )
1639 for pk in value:
1640 self.validate_no_null_characters(pk)
1641 try:
1642 self.queryset.filter(**{key: pk})
1643 except (ValueError, TypeError):
1644 raise ValidationError(
1645 self.error_messages["invalid_pk_value"],
1646 code="invalid_pk_value",
1647 params={"pk": pk},
1648 )
1649 qs = self.queryset.filter(**{"%s__in" % key: value})
1650 pks = {str(getattr(o, key)) for o in qs}
1651 for val in value:
1652 if str(val) not in pks:
1653 raise ValidationError(
1654 self.error_messages["invalid_choice"],
1655 code="invalid_choice",
1656 params={"value": val},
1657 )
1658 return qs
1659
1660 def prepare_value(self, value):
1661 if (
1662 hasattr(value, "__iter__")
1663 and not isinstance(value, str)
1664 and not hasattr(value, "_meta")
1665 ):
1666 prepare_value = super().prepare_value
1667 return [prepare_value(v) for v in value]
1668 return super().prepare_value(value)
1669
1670 def has_changed(self, initial, data):
1671 if self.disabled:
1672 return False
1673 if initial is None:
1674 initial = []
1675 if data is None:
1676 data = []
1677 if len(initial) != len(data):
1678 return True
1679 initial_set = {str(value) for value in self.prepare_value(initial)}
1680 data_set = {str(value) for value in data}
1681 return data_set != initial_set
1682
1683
1684def modelform_defines_fields(form_class):
1685 return hasattr(form_class, "_meta") and (
1686 form_class._meta.fields is not None or form_class._meta.exclude is not None
1687 )