1import functools
2import inspect
3from functools import partial
4
5from django import forms
6from django.apps import apps
7from django.conf import SettingsReference, settings
8from django.core import checks, exceptions
9from django.db import connection, router
10from django.db.backends import utils
11from django.db.models import Q
12from django.db.models.constants import LOOKUP_SEP
13from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL
14from django.db.models.query_utils import PathInfo
15from django.db.models.utils import make_model_tuple
16from django.utils.functional import cached_property
17from django.utils.translation import gettext_lazy as _
18
19from . import Field
20from .mixins import FieldCacheMixin
21from .related_descriptors import (
22 ForeignKeyDeferredAttribute,
23 ForwardManyToOneDescriptor,
24 ForwardOneToOneDescriptor,
25 ManyToManyDescriptor,
26 ReverseManyToOneDescriptor,
27 ReverseOneToOneDescriptor,
28)
29from .related_lookups import (
30 RelatedExact,
31 RelatedGreaterThan,
32 RelatedGreaterThanOrEqual,
33 RelatedIn,
34 RelatedIsNull,
35 RelatedLessThan,
36 RelatedLessThanOrEqual,
37)
38from .reverse_related import ForeignObjectRel, ManyToManyRel, ManyToOneRel, OneToOneRel
39
40RECURSIVE_RELATIONSHIP_CONSTANT = "self"
41
42
43def resolve_relation(scope_model, relation):
44 """
45 Transform relation into a model or fully-qualified model string of the form
46 "app_label.ModelName", relative to scope_model.
47
48 The relation argument can be:
49 * RECURSIVE_RELATIONSHIP_CONSTANT, i.e. the string "self", in which case
50 the model argument will be returned.
51 * A bare model name without an app_label, in which case scope_model's
52 app_label will be prepended.
53 * An "app_label.ModelName" string.
54 * A model class, which will be returned unchanged.
55 """
56 # Check for recursive relations
57 if relation == RECURSIVE_RELATIONSHIP_CONSTANT:
58 relation = scope_model
59
60 # Look for an "app.Model" relation
61 if isinstance(relation, str):
62 if "." not in relation:
63 relation = "%s.%s" % (scope_model._meta.app_label, relation)
64
65 return relation
66
67
68def lazy_related_operation(function, model, *related_models, **kwargs):
69 """
70 Schedule `function` to be called once `model` and all `related_models`
71 have been imported and registered with the app registry. `function` will
72 be called with the newly-loaded model classes as its positional arguments,
73 plus any optional keyword arguments.
74
75 The `model` argument must be a model class. Each subsequent positional
76 argument is another model, or a reference to another model - see
77 `resolve_relation()` for the various forms these may take. Any relative
78 references will be resolved relative to `model`.
79
80 This is a convenience wrapper for `Apps.lazy_model_operation` - the app
81 registry model used is the one found in `model._meta.apps`.
82 """
83 models = [model] + [resolve_relation(model, rel) for rel in related_models]
84 model_keys = (make_model_tuple(m) for m in models)
85 apps = model._meta.apps
86 return apps.lazy_model_operation(partial(function, **kwargs), *model_keys)
87
88
89class RelatedField(FieldCacheMixin, Field):
90 """Base class that all relational fields inherit from."""
91
92 # Field flags
93 one_to_many = False
94 one_to_one = False
95 many_to_many = False
96 many_to_one = False
97
98 def __init__(
99 self,
100 related_name=None,
101 related_query_name=None,
102 limit_choices_to=None,
103 **kwargs,
104 ):
105 self._related_name = related_name
106 self._related_query_name = related_query_name
107 self._limit_choices_to = limit_choices_to
108 super().__init__(**kwargs)
109
110 @cached_property
111 def related_model(self):
112 # Can't cache this property until all the models are loaded.
113 apps.check_models_ready()
114 return self.remote_field.model
115
116 def check(self, **kwargs):
117 return [
118 *super().check(**kwargs),
119 *self._check_related_name_is_valid(),
120 *self._check_related_query_name_is_valid(),
121 *self._check_relation_model_exists(),
122 *self._check_referencing_to_swapped_model(),
123 *self._check_clashes(),
124 ]
125
126 def _check_related_name_is_valid(self):
127 import keyword
128
129 related_name = self.remote_field.related_name
130 if related_name is None:
131 return []
132 is_valid_id = (
133 not keyword.iskeyword(related_name) and related_name.isidentifier()
134 )
135 if not (is_valid_id or related_name.endswith("+")):
136 return [
137 checks.Error(
138 "The name '%s' is invalid related_name for field %s.%s"
139 % (
140 self.remote_field.related_name,
141 self.model._meta.object_name,
142 self.name,
143 ),
144 hint=(
145 "Related name must be a valid Python identifier or end with a "
146 "'+'"
147 ),
148 obj=self,
149 id="fields.E306",
150 )
151 ]
152 return []
153
154 def _check_related_query_name_is_valid(self):
155 if self.remote_field.hidden:
156 return []
157 rel_query_name = self.related_query_name()
158 errors = []
159 if rel_query_name.endswith("_"):
160 errors.append(
161 checks.Error(
162 "Reverse query name '%s' must not end with an underscore."
163 % rel_query_name,
164 hint=(
165 "Add or change a related_name or related_query_name "
166 "argument for this field."
167 ),
168 obj=self,
169 id="fields.E308",
170 )
171 )
172 if LOOKUP_SEP in rel_query_name:
173 errors.append(
174 checks.Error(
175 "Reverse query name '%s' must not contain '%s'."
176 % (rel_query_name, LOOKUP_SEP),
177 hint=(
178 "Add or change a related_name or related_query_name "
179 "argument for this field."
180 ),
181 obj=self,
182 id="fields.E309",
183 )
184 )
185 return errors
186
187 def _check_relation_model_exists(self):
188 rel_is_missing = self.remote_field.model not in self.opts.apps.get_models(
189 include_auto_created=True
190 )
191 rel_is_string = isinstance(self.remote_field.model, str)
192 model_name = (
193 self.remote_field.model
194 if rel_is_string
195 else self.remote_field.model._meta.object_name
196 )
197 if rel_is_missing and (
198 rel_is_string or not self.remote_field.model._meta.swapped
199 ):
200 return [
201 checks.Error(
202 "Field defines a relation with model '%s', which is either "
203 "not installed, or is abstract." % model_name,
204 obj=self,
205 id="fields.E300",
206 )
207 ]
208 return []
209
210 def _check_referencing_to_swapped_model(self):
211 if (
212 self.remote_field.model not in self.opts.apps.get_models()
213 and not isinstance(self.remote_field.model, str)
214 and self.remote_field.model._meta.swapped
215 ):
216 return [
217 checks.Error(
218 "Field defines a relation with the model '%s', which has "
219 "been swapped out." % self.remote_field.model._meta.label,
220 hint="Update the relation to point at 'settings.%s'."
221 % self.remote_field.model._meta.swappable,
222 obj=self,
223 id="fields.E301",
224 )
225 ]
226 return []
227
228 def _check_clashes(self):
229 """Check accessor and reverse query name clashes."""
230 from django.db.models.base import ModelBase
231
232 errors = []
233 opts = self.model._meta
234
235 # f.remote_field.model may be a string instead of a model. Skip if
236 # model name is not resolved.
237 if not isinstance(self.remote_field.model, ModelBase):
238 return []
239
240 # Consider that we are checking field `Model.foreign` and the models
241 # are:
242 #
243 # class Target(models.Model):
244 # model = models.IntegerField()
245 # model_set = models.IntegerField()
246 #
247 # class Model(models.Model):
248 # foreign = models.ForeignKey(Target)
249 # m2m = models.ManyToManyField(Target)
250
251 # rel_opts.object_name == "Target"
252 rel_opts = self.remote_field.model._meta
253 # If the field doesn't install a backward relation on the target model
254 # (so `is_hidden` returns True), then there are no clashes to check
255 # and we can skip these fields.
256 rel_is_hidden = self.remote_field.hidden
257 rel_name = self.remote_field.accessor_name # i. e. "model_set"
258 rel_query_name = self.related_query_name() # i. e. "model"
259 # i.e. "app_label.Model.field".
260 field_name = "%s.%s" % (opts.label, self.name)
261
262 # Check clashes between accessor or reverse query name of `field`
263 # and any other field name -- i.e. accessor for Model.foreign is
264 # model_set and it clashes with Target.model_set.
265 potential_clashes = rel_opts.fields + rel_opts.many_to_many
266 for clash_field in potential_clashes:
267 if not rel_is_hidden and clash_field.name == rel_name:
268 clash_name = f"{rel_opts.label}.{clash_field.name}"
269 errors.append(
270 checks.Error(
271 f"Reverse accessor '{rel_opts.object_name}.{rel_name}' "
272 f"for '{field_name}' clashes with field name "
273 f"'{clash_name}'.",
274 hint=(
275 "Rename field '%s', or add/change a related_name "
276 "argument to the definition for field '%s'."
277 )
278 % (clash_name, field_name),
279 obj=self,
280 id="fields.E302",
281 )
282 )
283
284 if clash_field.name == rel_query_name:
285 clash_name = f"{rel_opts.label}.{clash_field.name}"
286 errors.append(
287 checks.Error(
288 "Reverse query name for '%s' clashes with field name '%s'."
289 % (field_name, clash_name),
290 hint=(
291 "Rename field '%s', or add/change a related_name "
292 "argument to the definition for field '%s'."
293 )
294 % (clash_name, field_name),
295 obj=self,
296 id="fields.E303",
297 )
298 )
299
300 # Check clashes between accessors/reverse query names of `field` and
301 # any other field accessor -- i. e. Model.foreign accessor clashes with
302 # Model.m2m accessor.
303 potential_clashes = (r for r in rel_opts.related_objects if r.field is not self)
304 for clash_field in potential_clashes:
305 if not rel_is_hidden and clash_field.accessor_name == rel_name:
306 clash_name = (
307 f"{clash_field.related_model._meta.label}.{clash_field.field.name}"
308 )
309 errors.append(
310 checks.Error(
311 f"Reverse accessor '{rel_opts.object_name}.{rel_name}' "
312 f"for '{field_name}' clashes with reverse accessor for "
313 f"'{clash_name}'.",
314 hint=(
315 "Add or change a related_name argument "
316 "to the definition for '%s' or '%s'."
317 )
318 % (field_name, clash_name),
319 obj=self,
320 id="fields.E304",
321 )
322 )
323
324 if clash_field.accessor_name == rel_query_name:
325 clash_name = (
326 f"{clash_field.related_model._meta.label}.{clash_field.field.name}"
327 )
328 errors.append(
329 checks.Error(
330 "Reverse query name for '%s' clashes with reverse query name "
331 "for '%s'." % (field_name, clash_name),
332 hint=(
333 "Add or change a related_name argument "
334 "to the definition for '%s' or '%s'."
335 )
336 % (field_name, clash_name),
337 obj=self,
338 id="fields.E305",
339 )
340 )
341
342 return errors
343
344 def db_type(self, connection):
345 # By default related field will not have a column as it relates to
346 # columns from another table.
347 return None
348
349 def contribute_to_class(self, cls, name, private_only=False, **kwargs):
350 super().contribute_to_class(cls, name, private_only=private_only, **kwargs)
351
352 self.opts = cls._meta
353
354 if not cls._meta.abstract:
355 if self.remote_field.related_name:
356 related_name = self.remote_field.related_name
357 else:
358 related_name = self.opts.default_related_name
359 if related_name:
360 related_name %= {
361 "class": cls.__name__.lower(),
362 "model_name": cls._meta.model_name.lower(),
363 "app_label": cls._meta.app_label.lower(),
364 }
365 self.remote_field.related_name = related_name
366
367 if self.remote_field.related_query_name:
368 related_query_name = self.remote_field.related_query_name % {
369 "class": cls.__name__.lower(),
370 "app_label": cls._meta.app_label.lower(),
371 }
372 self.remote_field.related_query_name = related_query_name
373
374 def resolve_related_class(model, related, field):
375 field.remote_field.model = related
376 field.do_related_class(related, model)
377
378 lazy_related_operation(
379 resolve_related_class, cls, self.remote_field.model, field=self
380 )
381
382 def deconstruct(self):
383 name, path, args, kwargs = super().deconstruct()
384 if self._limit_choices_to:
385 kwargs["limit_choices_to"] = self._limit_choices_to
386 if self._related_name is not None:
387 kwargs["related_name"] = self._related_name
388 if self._related_query_name is not None:
389 kwargs["related_query_name"] = self._related_query_name
390 return name, path, args, kwargs
391
392 def get_forward_related_filter(self, obj):
393 """
394 Return the keyword arguments that when supplied to
395 self.model.object.filter(), would select all instances related through
396 this field to the remote obj. This is used to build the querysets
397 returned by related descriptors. obj is an instance of
398 self.related_field.model.
399 """
400 return {
401 "%s__%s" % (self.name, rh_field.name): getattr(obj, rh_field.attname)
402 for _, rh_field in self.related_fields
403 }
404
405 def get_reverse_related_filter(self, obj):
406 """
407 Complement to get_forward_related_filter(). Return the keyword
408 arguments that when passed to self.related_field.model.object.filter()
409 select all instances of self.related_field.model related through
410 this field to obj. obj is an instance of self.model.
411 """
412 base_q = Q.create(
413 [
414 (rh_field.attname, getattr(obj, lh_field.attname))
415 for lh_field, rh_field in self.related_fields
416 ]
417 )
418 descriptor_filter = self.get_extra_descriptor_filter(obj)
419 if isinstance(descriptor_filter, dict):
420 return base_q & Q(**descriptor_filter)
421 elif descriptor_filter:
422 return base_q & descriptor_filter
423 return base_q
424
425 @property
426 def swappable_setting(self):
427 """
428 Get the setting that this is powered from for swapping, or None
429 if it's not swapped in / marked with swappable=False.
430 """
431 if self.swappable:
432 # Work out string form of "to"
433 if isinstance(self.remote_field.model, str):
434 to_string = self.remote_field.model
435 else:
436 to_string = self.remote_field.model._meta.label
437 return apps.get_swappable_settings_name(to_string)
438 return None
439
440 def set_attributes_from_rel(self):
441 self.name = self.name or (
442 self.remote_field.model._meta.model_name
443 + "_"
444 + self.remote_field.model._meta.pk.name
445 )
446 if self.verbose_name is None:
447 self.verbose_name = self.remote_field.model._meta.verbose_name
448 self.remote_field.set_field_name()
449
450 def do_related_class(self, other, cls):
451 self.set_attributes_from_rel()
452 self.contribute_to_related_class(other, self.remote_field)
453
454 def get_limit_choices_to(self):
455 """
456 Return ``limit_choices_to`` for this model field.
457
458 If it is a callable, it will be invoked and the result will be
459 returned.
460 """
461 if callable(self.remote_field.limit_choices_to):
462 return self.remote_field.limit_choices_to()
463 return self.remote_field.limit_choices_to
464
465 def formfield(self, **kwargs):
466 """
467 Pass ``limit_choices_to`` to the field being constructed.
468
469 Only passes it if there is a type that supports related fields.
470 This is a similar strategy used to pass the ``queryset`` to the field
471 being constructed.
472 """
473 defaults = {}
474 if hasattr(self.remote_field, "get_related_field"):
475 # If this is a callable, do not invoke it here. Just pass
476 # it in the defaults for when the form class will later be
477 # instantiated.
478 limit_choices_to = self.remote_field.limit_choices_to
479 defaults.update(
480 {
481 "limit_choices_to": limit_choices_to,
482 }
483 )
484 defaults.update(kwargs)
485 return super().formfield(**defaults)
486
487 def related_query_name(self):
488 """
489 Define the name that can be used to identify this related object in a
490 table-spanning query.
491 """
492 return (
493 self.remote_field.related_query_name
494 or self.remote_field.related_name
495 or self.opts.model_name
496 )
497
498 @property
499 def target_field(self):
500 """
501 When filtering against this relation, return the field on the remote
502 model against which the filtering should happen.
503 """
504 target_fields = self.path_infos[-1].target_fields
505 if len(target_fields) > 1:
506 raise exceptions.FieldError(
507 "The relation has multiple target fields, but only single target field "
508 "was asked for"
509 )
510 return target_fields[0]
511
512 @cached_property
513 def cache_name(self):
514 return self.name
515
516
517class ForeignObject(RelatedField):
518 """
519 Abstraction of the ForeignKey relation to support multi-column relations.
520 """
521
522 # Field flags
523 many_to_many = False
524 many_to_one = True
525 one_to_many = False
526 one_to_one = False
527
528 requires_unique_target = True
529 related_accessor_class = ReverseManyToOneDescriptor
530 forward_related_accessor_class = ForwardManyToOneDescriptor
531 rel_class = ForeignObjectRel
532
533 def __init__(
534 self,
535 to,
536 on_delete,
537 from_fields,
538 to_fields,
539 rel=None,
540 related_name=None,
541 related_query_name=None,
542 limit_choices_to=None,
543 parent_link=False,
544 swappable=True,
545 **kwargs,
546 ):
547 if rel is None:
548 rel = self.rel_class(
549 self,
550 to,
551 related_name=related_name,
552 related_query_name=related_query_name,
553 limit_choices_to=limit_choices_to,
554 parent_link=parent_link,
555 on_delete=on_delete,
556 )
557
558 super().__init__(
559 rel=rel,
560 related_name=related_name,
561 related_query_name=related_query_name,
562 limit_choices_to=limit_choices_to,
563 **kwargs,
564 )
565
566 self.from_fields = from_fields
567 self.to_fields = to_fields
568 self.swappable = swappable
569
570 def __copy__(self):
571 obj = super().__copy__()
572 # Remove any cached PathInfo values.
573 obj.__dict__.pop("path_infos", None)
574 obj.__dict__.pop("reverse_path_infos", None)
575 return obj
576
577 def check(self, **kwargs):
578 return [
579 *super().check(**kwargs),
580 *self._check_to_fields_exist(),
581 *self._check_to_fields_composite_pk(),
582 *self._check_unique_target(),
583 ]
584
585 def _check_to_fields_exist(self):
586 # Skip nonexistent models.
587 if isinstance(self.remote_field.model, str):
588 return []
589
590 errors = []
591 for to_field in self.to_fields:
592 if to_field:
593 try:
594 self.remote_field.model._meta.get_field(to_field)
595 except exceptions.FieldDoesNotExist:
596 errors.append(
597 checks.Error(
598 "The to_field '%s' doesn't exist on the related "
599 "model '%s'."
600 % (to_field, self.remote_field.model._meta.label),
601 obj=self,
602 id="fields.E312",
603 )
604 )
605 return errors
606
607 def _check_to_fields_composite_pk(self):
608 from django.db.models.fields.composite import CompositePrimaryKey
609
610 # Skip nonexistent models.
611 if isinstance(self.remote_field.model, str):
612 return []
613
614 errors = []
615 for to_field in self.to_fields:
616 try:
617 field = (
618 self.remote_field.model._meta.pk
619 if to_field is None
620 else self.remote_field.model._meta.get_field(to_field)
621 )
622 except exceptions.FieldDoesNotExist:
623 pass
624 else:
625 if isinstance(field, CompositePrimaryKey):
626 errors.append(
627 checks.Error(
628 "Field defines a relation to the CompositePrimaryKey of "
629 f"model {self.remote_field.model._meta.object_name!r} "
630 "which is not supported.",
631 obj=self,
632 id="fields.E347",
633 )
634 )
635 return errors
636
637 def _check_unique_target(self):
638 rel_is_string = isinstance(self.remote_field.model, str)
639 if rel_is_string or not self.requires_unique_target:
640 return []
641
642 try:
643 self.foreign_related_fields
644 except exceptions.FieldDoesNotExist:
645 return []
646
647 if not self.foreign_related_fields:
648 return []
649
650 has_unique_constraint = any(
651 rel_field.unique for rel_field in self.foreign_related_fields
652 )
653 if not has_unique_constraint:
654 foreign_fields = {f.name for f in self.foreign_related_fields}
655 remote_opts = self.remote_field.model._meta
656 has_unique_constraint = (
657 any(
658 frozenset(ut) <= foreign_fields
659 for ut in remote_opts.unique_together
660 )
661 or any(
662 frozenset(uc.fields) <= foreign_fields
663 for uc in remote_opts.total_unique_constraints
664 )
665 # If the model defines a composite primary key and the foreign key
666 # refers to it, the target is unique.
667 or (
668 frozenset(field.name for field in remote_opts.pk_fields)
669 == foreign_fields
670 )
671 )
672
673 if not has_unique_constraint:
674 if len(self.foreign_related_fields) > 1:
675 field_combination = ", ".join(
676 f"'{rel_field.name}'" for rel_field in self.foreign_related_fields
677 )
678 model_name = self.remote_field.model.__name__
679 return [
680 checks.Error(
681 f"No subset of the fields {field_combination} on model "
682 f"'{model_name}' is unique.",
683 hint=(
684 "Mark a single field as unique=True or add a set of "
685 "fields to a unique constraint (via unique_together "
686 "or a UniqueConstraint (without condition) in the "
687 "model Meta.constraints)."
688 ),
689 obj=self,
690 id="fields.E310",
691 )
692 ]
693 else:
694 field_name = self.foreign_related_fields[0].name
695 model_name = self.remote_field.model.__name__
696 return [
697 checks.Error(
698 f"'{model_name}.{field_name}' must be unique because it is "
699 "referenced by a foreign key.",
700 hint=(
701 "Add unique=True to this field or add a "
702 "UniqueConstraint (without condition) in the model "
703 "Meta.constraints."
704 ),
705 obj=self,
706 id="fields.E311",
707 )
708 ]
709 return []
710
711 def deconstruct(self):
712 name, path, args, kwargs = super().deconstruct()
713 kwargs["on_delete"] = self.remote_field.on_delete
714 kwargs["from_fields"] = self.from_fields
715 kwargs["to_fields"] = self.to_fields
716
717 if self.remote_field.parent_link:
718 kwargs["parent_link"] = self.remote_field.parent_link
719 if isinstance(self.remote_field.model, str):
720 if "." in self.remote_field.model:
721 app_label, model_name = self.remote_field.model.split(".")
722 kwargs["to"] = "%s.%s" % (app_label, model_name.lower())
723 else:
724 kwargs["to"] = self.remote_field.model.lower()
725 else:
726 kwargs["to"] = self.remote_field.model._meta.label_lower
727 # If swappable is True, then see if we're actually pointing to the target
728 # of a swap.
729 swappable_setting = self.swappable_setting
730 if swappable_setting is not None:
731 # If it's already a settings reference, error
732 if hasattr(kwargs["to"], "setting_name"):
733 if kwargs["to"].setting_name != swappable_setting:
734 raise ValueError(
735 "Cannot deconstruct a ForeignKey pointing to a model "
736 "that is swapped in place of more than one model (%s and %s)"
737 % (kwargs["to"].setting_name, swappable_setting)
738 )
739 # Set it
740 kwargs["to"] = SettingsReference(
741 kwargs["to"],
742 swappable_setting,
743 )
744 return name, path, args, kwargs
745
746 def resolve_related_fields(self):
747 if not self.from_fields or len(self.from_fields) != len(self.to_fields):
748 raise ValueError(
749 "Foreign Object from and to fields must be the same non-zero length"
750 )
751 if isinstance(self.remote_field.model, str):
752 raise ValueError(
753 "Related model %r cannot be resolved" % self.remote_field.model
754 )
755 related_fields = []
756 for from_field_name, to_field_name in zip(self.from_fields, self.to_fields):
757 from_field = (
758 self
759 if from_field_name == RECURSIVE_RELATIONSHIP_CONSTANT
760 else self.opts.get_field(from_field_name)
761 )
762 to_field = (
763 self.remote_field.model._meta.pk
764 if to_field_name is None
765 else self.remote_field.model._meta.get_field(to_field_name)
766 )
767 related_fields.append((from_field, to_field))
768 return related_fields
769
770 @cached_property
771 def related_fields(self):
772 return self.resolve_related_fields()
773
774 @cached_property
775 def reverse_related_fields(self):
776 return [(rhs_field, lhs_field) for lhs_field, rhs_field in self.related_fields]
777
778 @cached_property
779 def local_related_fields(self):
780 return tuple(lhs_field for lhs_field, rhs_field in self.related_fields)
781
782 @cached_property
783 def foreign_related_fields(self):
784 return tuple(
785 rhs_field for lhs_field, rhs_field in self.related_fields if rhs_field
786 )
787
788 def get_local_related_value(self, instance):
789 return self.get_instance_value_for_fields(instance, self.local_related_fields)
790
791 def get_foreign_related_value(self, instance):
792 return self.get_instance_value_for_fields(instance, self.foreign_related_fields)
793
794 @staticmethod
795 def get_instance_value_for_fields(instance, fields):
796 ret = []
797 opts = instance._meta
798 for field in fields:
799 # Gotcha: in some cases (like fixture loading) a model can have
800 # different values in parent_ptr_id and parent's id. So, use
801 # instance.pk (that is, parent_ptr_id) when asked for instance.id.
802 if field.primary_key:
803 possible_parent_link = opts.get_ancestor_link(field.model)
804 if (
805 not possible_parent_link
806 or possible_parent_link.primary_key
807 or possible_parent_link.model._meta.abstract
808 ):
809 ret.append(instance.pk)
810 continue
811 ret.append(getattr(instance, field.attname))
812 return tuple(ret)
813
814 def get_attname_column(self):
815 attname, column = super().get_attname_column()
816 return attname, None
817
818 def get_joining_fields(self, reverse_join=False):
819 return tuple(
820 self.reverse_related_fields if reverse_join else self.related_fields
821 )
822
823 def get_reverse_joining_fields(self):
824 return self.get_joining_fields(reverse_join=True)
825
826 def get_extra_descriptor_filter(self, instance):
827 """
828 Return an extra filter condition for related object fetching when
829 user does 'instance.fieldname', that is the extra filter is used in
830 the descriptor of the field.
831
832 The filter should be either a dict usable in .filter(**kwargs) call or
833 a Q-object. The condition will be ANDed together with the relation's
834 joining columns.
835
836 A parallel method is get_extra_restriction() which is used in
837 JOIN and subquery conditions.
838 """
839 return {}
840
841 def get_extra_restriction(self, alias, related_alias):
842 """
843 Return a pair condition used for joining and subquery pushdown. The
844 condition is something that responds to as_sql(compiler, connection)
845 method.
846
847 Note that currently referring both the 'alias' and 'related_alias'
848 will not work in some conditions, like subquery pushdown.
849
850 A parallel method is get_extra_descriptor_filter() which is used in
851 instance.fieldname related object fetching.
852 """
853 return None
854
855 def get_path_info(self, filtered_relation=None):
856 """Get path from this field to the related model."""
857 opts = self.remote_field.model._meta
858 from_opts = self.model._meta
859 return [
860 PathInfo(
861 from_opts=from_opts,
862 to_opts=opts,
863 target_fields=self.foreign_related_fields,
864 join_field=self,
865 m2m=False,
866 direct=True,
867 filtered_relation=filtered_relation,
868 )
869 ]
870
871 @cached_property
872 def path_infos(self):
873 return self.get_path_info()
874
875 def get_reverse_path_info(self, filtered_relation=None):
876 """Get path from the related model to this field's model."""
877 opts = self.model._meta
878 from_opts = self.remote_field.model._meta
879 return [
880 PathInfo(
881 from_opts=from_opts,
882 to_opts=opts,
883 target_fields=(opts.pk,),
884 join_field=self.remote_field,
885 m2m=not self.unique,
886 direct=False,
887 filtered_relation=filtered_relation,
888 )
889 ]
890
891 @cached_property
892 def reverse_path_infos(self):
893 return self.get_reverse_path_info()
894
895 @classmethod
896 @functools.cache
897 def get_class_lookups(cls):
898 bases = inspect.getmro(cls)
899 bases = bases[: bases.index(ForeignObject) + 1]
900 class_lookups = [parent.__dict__.get("class_lookups", {}) for parent in bases]
901 return cls.merge_dicts(class_lookups)
902
903 def contribute_to_class(self, cls, name, private_only=False, **kwargs):
904 super().contribute_to_class(cls, name, private_only=private_only, **kwargs)
905 setattr(cls, self.name, self.forward_related_accessor_class(self))
906
907 def contribute_to_related_class(self, cls, related):
908 # Internal FK's - i.e., those with a related name ending with '+' -
909 # and swapped models don't get a related descriptor.
910 if not self.remote_field.hidden and not related.related_model._meta.swapped:
911 setattr(
912 cls._meta.concrete_model,
913 related.accessor_name,
914 self.related_accessor_class(related),
915 )
916 # While 'limit_choices_to' might be a callable, simply pass
917 # it along for later - this is too early because it's still
918 # model load time.
919 if self.remote_field.limit_choices_to:
920 cls._meta.related_fkey_lookups.append(
921 self.remote_field.limit_choices_to
922 )
923
924
925ForeignObject.register_lookup(RelatedIn)
926ForeignObject.register_lookup(RelatedExact)
927ForeignObject.register_lookup(RelatedLessThan)
928ForeignObject.register_lookup(RelatedGreaterThan)
929ForeignObject.register_lookup(RelatedGreaterThanOrEqual)
930ForeignObject.register_lookup(RelatedLessThanOrEqual)
931ForeignObject.register_lookup(RelatedIsNull)
932
933
934class ForeignKey(ForeignObject):
935 """
936 Provide a many-to-one relation by adding a column to the local model
937 to hold the remote value.
938
939 By default ForeignKey will target the pk of the remote model but this
940 behavior can be changed by using the ``to_field`` argument.
941 """
942
943 descriptor_class = ForeignKeyDeferredAttribute
944 # Field flags
945 many_to_many = False
946 many_to_one = True
947 one_to_many = False
948 one_to_one = False
949
950 rel_class = ManyToOneRel
951
952 empty_strings_allowed = False
953 default_error_messages = {
954 "invalid": _(
955 "%(model)s instance with %(field)s %(value)r is not a valid choice."
956 )
957 }
958 description = _("Foreign Key (type determined by related field)")
959
960 def __init__(
961 self,
962 to,
963 on_delete,
964 related_name=None,
965 related_query_name=None,
966 limit_choices_to=None,
967 parent_link=False,
968 to_field=None,
969 db_constraint=True,
970 **kwargs,
971 ):
972 try:
973 to._meta.model_name
974 except AttributeError:
975 if not isinstance(to, str):
976 raise TypeError(
977 "%s(%r) is invalid. First parameter to ForeignKey must be "
978 "either a model, a model name, or the string %r"
979 % (
980 self.__class__.__name__,
981 to,
982 RECURSIVE_RELATIONSHIP_CONSTANT,
983 )
984 )
985 else:
986 # For backwards compatibility purposes, we need to *try* and set
987 # the to_field during FK construction. It won't be guaranteed to
988 # be correct until contribute_to_class is called. Refs #12190.
989 to_field = to_field or (to._meta.pk and to._meta.pk.name)
990 if not callable(on_delete):
991 raise TypeError("on_delete must be callable.")
992
993 kwargs["rel"] = self.rel_class(
994 self,
995 to,
996 to_field,
997 related_name=related_name,
998 related_query_name=related_query_name,
999 limit_choices_to=limit_choices_to,
1000 parent_link=parent_link,
1001 on_delete=on_delete,
1002 )
1003 kwargs.setdefault("db_index", True)
1004
1005 super().__init__(
1006 to,
1007 on_delete,
1008 related_name=related_name,
1009 related_query_name=related_query_name,
1010 limit_choices_to=limit_choices_to,
1011 from_fields=[RECURSIVE_RELATIONSHIP_CONSTANT],
1012 to_fields=[to_field],
1013 **kwargs,
1014 )
1015 self.db_constraint = db_constraint
1016
1017 def __class_getitem__(cls, *args, **kwargs):
1018 return cls
1019
1020 def check(self, **kwargs):
1021 return [
1022 *super().check(**kwargs),
1023 *self._check_on_delete(),
1024 *self._check_unique(),
1025 ]
1026
1027 def _check_on_delete(self):
1028 on_delete = getattr(self.remote_field, "on_delete", None)
1029 if on_delete == SET_NULL and not self.null:
1030 return [
1031 checks.Error(
1032 "Field specifies on_delete=SET_NULL, but cannot be null.",
1033 hint=(
1034 "Set null=True argument on the field, or change the on_delete "
1035 "rule."
1036 ),
1037 obj=self,
1038 id="fields.E320",
1039 )
1040 ]
1041 elif on_delete == SET_DEFAULT and not self.has_default():
1042 return [
1043 checks.Error(
1044 "Field specifies on_delete=SET_DEFAULT, but has no default value.",
1045 hint="Set a default value, or change the on_delete rule.",
1046 obj=self,
1047 id="fields.E321",
1048 )
1049 ]
1050 else:
1051 return []
1052
1053 def _check_unique(self, **kwargs):
1054 return (
1055 [
1056 checks.Warning(
1057 "Setting unique=True on a ForeignKey has the same effect as using "
1058 "a OneToOneField.",
1059 hint=(
1060 "ForeignKey(unique=True) is usually better served by a "
1061 "OneToOneField."
1062 ),
1063 obj=self,
1064 id="fields.W342",
1065 )
1066 ]
1067 if self.unique
1068 else []
1069 )
1070
1071 def deconstruct(self):
1072 name, path, args, kwargs = super().deconstruct()
1073 del kwargs["to_fields"]
1074 del kwargs["from_fields"]
1075 # Handle the simpler arguments
1076 if self.db_index:
1077 del kwargs["db_index"]
1078 else:
1079 kwargs["db_index"] = False
1080 if self.db_constraint is not True:
1081 kwargs["db_constraint"] = self.db_constraint
1082 # Rel needs more work.
1083 to_meta = getattr(self.remote_field.model, "_meta", None)
1084 if self.remote_field.field_name and (
1085 not to_meta
1086 or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name)
1087 ):
1088 kwargs["to_field"] = self.remote_field.field_name
1089 return name, path, args, kwargs
1090
1091 def to_python(self, value):
1092 return self.target_field.to_python(value)
1093
1094 @property
1095 def target_field(self):
1096 return self.foreign_related_fields[0]
1097
1098 def validate(self, value, model_instance):
1099 if self.remote_field.parent_link:
1100 return
1101 super().validate(value, model_instance)
1102 if value is None:
1103 return
1104
1105 using = router.db_for_read(self.remote_field.model, instance=model_instance)
1106 qs = self.remote_field.model._base_manager.using(using).filter(
1107 **{self.remote_field.field_name: value}
1108 )
1109 qs = qs.complex_filter(self.get_limit_choices_to())
1110 if not qs.exists():
1111 raise exceptions.ValidationError(
1112 self.error_messages["invalid"],
1113 code="invalid",
1114 params={
1115 "model": self.remote_field.model._meta.verbose_name,
1116 "pk": value,
1117 "field": self.remote_field.field_name,
1118 "value": value,
1119 }, # 'pk' is included for backwards compatibility
1120 )
1121
1122 def resolve_related_fields(self):
1123 related_fields = super().resolve_related_fields()
1124 for from_field, to_field in related_fields:
1125 if (
1126 to_field
1127 and to_field.model != self.remote_field.model._meta.concrete_model
1128 ):
1129 raise exceptions.FieldError(
1130 "'%s.%s' refers to field '%s' which is not local to model "
1131 "'%s'."
1132 % (
1133 self.model._meta.label,
1134 self.name,
1135 to_field.name,
1136 self.remote_field.model._meta.concrete_model._meta.label,
1137 )
1138 )
1139 return related_fields
1140
1141 def get_attname(self):
1142 return "%s_id" % self.name
1143
1144 def get_attname_column(self):
1145 attname = self.get_attname()
1146 column = self.db_column or attname
1147 return attname, column
1148
1149 def get_default(self):
1150 """Return the to_field if the default value is an object."""
1151 field_default = super().get_default()
1152 if isinstance(field_default, self.remote_field.model):
1153 return getattr(field_default, self.target_field.attname)
1154 return field_default
1155
1156 def get_db_prep_save(self, value, connection):
1157 if value is None or (
1158 value == ""
1159 and (
1160 not self.target_field.empty_strings_allowed
1161 or connection.features.interprets_empty_strings_as_nulls
1162 )
1163 ):
1164 return None
1165 else:
1166 return self.target_field.get_db_prep_save(value, connection=connection)
1167
1168 def get_db_prep_value(self, value, connection, prepared=False):
1169 return self.target_field.get_db_prep_value(value, connection, prepared)
1170
1171 def get_prep_value(self, value):
1172 return self.target_field.get_prep_value(value)
1173
1174 def contribute_to_related_class(self, cls, related):
1175 super().contribute_to_related_class(cls, related)
1176 if self.remote_field.field_name is None:
1177 self.remote_field.field_name = cls._meta.pk.name
1178
1179 def formfield(self, *, using=None, **kwargs):
1180 if isinstance(self.remote_field.model, str):
1181 raise ValueError(
1182 "Cannot create form field for %r yet, because "
1183 "its related model %r has not been loaded yet"
1184 % (self.name, self.remote_field.model)
1185 )
1186 return super().formfield(
1187 **{
1188 "form_class": forms.ModelChoiceField,
1189 "queryset": self.remote_field.model._default_manager.using(using),
1190 "to_field_name": self.remote_field.field_name,
1191 **kwargs,
1192 "blank": self.blank,
1193 }
1194 )
1195
1196 def db_check(self, connection):
1197 return None
1198
1199 def db_type(self, connection):
1200 return self.target_field.rel_db_type(connection=connection)
1201
1202 def cast_db_type(self, connection):
1203 return self.target_field.cast_db_type(connection=connection)
1204
1205 def db_parameters(self, connection):
1206 target_db_parameters = self.target_field.db_parameters(connection)
1207 return {
1208 "type": self.db_type(connection),
1209 "check": self.db_check(connection),
1210 "collation": target_db_parameters.get("collation"),
1211 }
1212
1213 def convert_empty_strings(self, value, expression, connection):
1214 if (not value) and isinstance(value, str):
1215 return None
1216 return value
1217
1218 def get_db_converters(self, connection):
1219 converters = super().get_db_converters(connection)
1220 if connection.features.interprets_empty_strings_as_nulls:
1221 converters += [self.convert_empty_strings]
1222 return converters
1223
1224 def get_col(self, alias, output_field=None):
1225 if output_field is None:
1226 output_field = self.target_field
1227 while isinstance(output_field, ForeignKey):
1228 output_field = output_field.target_field
1229 if output_field is self:
1230 raise ValueError("Cannot resolve output_field.")
1231 return super().get_col(alias, output_field)
1232
1233
1234class OneToOneField(ForeignKey):
1235 """
1236 A OneToOneField is essentially the same as a ForeignKey, with the exception
1237 that it always carries a "unique" constraint with it and the reverse
1238 relation always returns the object pointed to (since there will only ever
1239 be one), rather than returning a list.
1240 """
1241
1242 # Field flags
1243 many_to_many = False
1244 many_to_one = False
1245 one_to_many = False
1246 one_to_one = True
1247
1248 related_accessor_class = ReverseOneToOneDescriptor
1249 forward_related_accessor_class = ForwardOneToOneDescriptor
1250 rel_class = OneToOneRel
1251
1252 description = _("One-to-one relationship")
1253
1254 def __init__(self, to, on_delete, to_field=None, **kwargs):
1255 kwargs["unique"] = True
1256 super().__init__(to, on_delete, to_field=to_field, **kwargs)
1257
1258 def deconstruct(self):
1259 name, path, args, kwargs = super().deconstruct()
1260 if "unique" in kwargs:
1261 del kwargs["unique"]
1262 return name, path, args, kwargs
1263
1264 def formfield(self, **kwargs):
1265 if self.remote_field.parent_link:
1266 return None
1267 return super().formfield(**kwargs)
1268
1269 def save_form_data(self, instance, data):
1270 if isinstance(data, self.remote_field.model):
1271 setattr(instance, self.name, data)
1272 else:
1273 setattr(instance, self.attname, data)
1274 # Remote field object must be cleared otherwise Model.save()
1275 # will reassign attname using the related object pk.
1276 if data is None:
1277 setattr(instance, self.name, data)
1278
1279 def _check_unique(self, **kwargs):
1280 # Override ForeignKey since check isn't applicable here.
1281 return []
1282
1283
1284def create_many_to_many_intermediary_model(field, klass):
1285 from django.db import models
1286
1287 def set_managed(model, related, through):
1288 through._meta.managed = model._meta.managed or related._meta.managed
1289
1290 to_model = resolve_relation(klass, field.remote_field.model)
1291 name = "%s_%s" % (klass._meta.object_name, field.name)
1292 lazy_related_operation(set_managed, klass, to_model, name)
1293
1294 to = make_model_tuple(to_model)[1]
1295 from_ = klass._meta.model_name
1296 if to == from_:
1297 to = "to_%s" % to
1298 from_ = "from_%s" % from_
1299
1300 meta = type(
1301 "Meta",
1302 (),
1303 {
1304 "db_table": field._get_m2m_db_table(klass._meta),
1305 "auto_created": klass,
1306 "app_label": klass._meta.app_label,
1307 "db_tablespace": klass._meta.db_tablespace,
1308 "unique_together": (from_, to),
1309 "verbose_name": _("%(from)s-%(to)s relationship")
1310 % {"from": from_, "to": to},
1311 "verbose_name_plural": _("%(from)s-%(to)s relationships")
1312 % {"from": from_, "to": to},
1313 "apps": field.model._meta.apps,
1314 },
1315 )
1316 # Construct and return the new class.
1317 return type(
1318 name,
1319 (models.Model,),
1320 {
1321 "Meta": meta,
1322 "__module__": klass.__module__,
1323 from_: models.ForeignKey(
1324 klass,
1325 related_name="%s+" % name,
1326 db_tablespace=field.db_tablespace,
1327 db_constraint=field.remote_field.db_constraint,
1328 on_delete=CASCADE,
1329 ),
1330 to: models.ForeignKey(
1331 to_model,
1332 related_name="%s+" % name,
1333 db_tablespace=field.db_tablespace,
1334 db_constraint=field.remote_field.db_constraint,
1335 on_delete=CASCADE,
1336 ),
1337 },
1338 )
1339
1340
1341class ManyToManyField(RelatedField):
1342 """
1343 Provide a many-to-many relation by using an intermediary model that
1344 holds two ForeignKey fields pointed at the two sides of the relation.
1345
1346 Unless a ``through`` model was provided, ManyToManyField will use the
1347 create_many_to_many_intermediary_model factory to automatically generate
1348 the intermediary model.
1349 """
1350
1351 # Field flags
1352 many_to_many = True
1353 many_to_one = False
1354 one_to_many = False
1355 one_to_one = False
1356
1357 rel_class = ManyToManyRel
1358
1359 description = _("Many-to-many relationship")
1360
1361 def __init__(
1362 self,
1363 to,
1364 related_name=None,
1365 related_query_name=None,
1366 limit_choices_to=None,
1367 symmetrical=None,
1368 through=None,
1369 through_fields=None,
1370 db_constraint=True,
1371 db_table=None,
1372 swappable=True,
1373 **kwargs,
1374 ):
1375 try:
1376 to._meta
1377 except AttributeError:
1378 if not isinstance(to, str):
1379 raise TypeError(
1380 "%s(%r) is invalid. First parameter to ManyToManyField "
1381 "must be either a model, a model name, or the string %r"
1382 % (
1383 self.__class__.__name__,
1384 to,
1385 RECURSIVE_RELATIONSHIP_CONSTANT,
1386 )
1387 )
1388
1389 if symmetrical is None:
1390 symmetrical = to == RECURSIVE_RELATIONSHIP_CONSTANT
1391
1392 if through is not None and db_table is not None:
1393 raise ValueError(
1394 "Cannot specify a db_table if an intermediary model is used."
1395 )
1396
1397 kwargs["rel"] = self.rel_class(
1398 self,
1399 to,
1400 related_name=related_name,
1401 related_query_name=related_query_name,
1402 limit_choices_to=limit_choices_to,
1403 symmetrical=symmetrical,
1404 through=through,
1405 through_fields=through_fields,
1406 db_constraint=db_constraint,
1407 )
1408 self.has_null_arg = "null" in kwargs
1409
1410 super().__init__(
1411 related_name=related_name,
1412 related_query_name=related_query_name,
1413 limit_choices_to=limit_choices_to,
1414 **kwargs,
1415 )
1416
1417 self.db_table = db_table
1418 self.swappable = swappable
1419
1420 def check(self, **kwargs):
1421 return [
1422 *super().check(**kwargs),
1423 *self._check_unique(**kwargs),
1424 *self._check_relationship_model(**kwargs),
1425 *self._check_ignored_options(**kwargs),
1426 *self._check_table_uniqueness(**kwargs),
1427 ]
1428
1429 def _check_unique(self, **kwargs):
1430 if self.unique:
1431 return [
1432 checks.Error(
1433 "ManyToManyFields cannot be unique.",
1434 obj=self,
1435 id="fields.E330",
1436 )
1437 ]
1438 return []
1439
1440 def _check_ignored_options(self, **kwargs):
1441 warnings = []
1442
1443 if self.has_null_arg:
1444 warnings.append(
1445 checks.Warning(
1446 "null has no effect on ManyToManyField.",
1447 obj=self,
1448 id="fields.W340",
1449 )
1450 )
1451
1452 if self._validators:
1453 warnings.append(
1454 checks.Warning(
1455 "ManyToManyField does not support validators.",
1456 obj=self,
1457 id="fields.W341",
1458 )
1459 )
1460 if self.remote_field.symmetrical and self._related_name:
1461 warnings.append(
1462 checks.Warning(
1463 "related_name has no effect on ManyToManyField "
1464 'with a symmetrical relationship, e.g. to "self".',
1465 obj=self,
1466 id="fields.W345",
1467 )
1468 )
1469 if self.db_comment:
1470 warnings.append(
1471 checks.Warning(
1472 "db_comment has no effect on ManyToManyField.",
1473 obj=self,
1474 id="fields.W346",
1475 )
1476 )
1477
1478 return warnings
1479
1480 def _check_relationship_model(self, from_model=None, **kwargs):
1481 from django.db.models.fields.composite import CompositePrimaryKey
1482
1483 if hasattr(self.remote_field.through, "_meta"):
1484 qualified_model_name = "%s.%s" % (
1485 self.remote_field.through._meta.app_label,
1486 self.remote_field.through.__name__,
1487 )
1488 else:
1489 qualified_model_name = self.remote_field.through
1490
1491 errors = []
1492
1493 if self.remote_field.through not in self.opts.apps.get_models(
1494 include_auto_created=True
1495 ):
1496 # The relationship model is not installed.
1497 errors.append(
1498 checks.Error(
1499 "Field specifies a many-to-many relation through model "
1500 "'%s', which has not been installed." % qualified_model_name,
1501 obj=self,
1502 id="fields.E331",
1503 )
1504 )
1505
1506 else:
1507 assert from_model is not None, (
1508 "ManyToManyField with intermediate "
1509 "tables cannot be checked if you don't pass the model "
1510 "where the field is attached to."
1511 )
1512 # Set some useful local variables
1513 to_model = resolve_relation(from_model, self.remote_field.model)
1514 from_model_name = from_model._meta.object_name
1515 if isinstance(to_model, str):
1516 to_model_name = to_model
1517 else:
1518 to_model_name = to_model._meta.object_name
1519 if (
1520 self.remote_field.through_fields is None
1521 and not isinstance(to_model, str)
1522 and isinstance(to_model._meta.pk, CompositePrimaryKey)
1523 ):
1524 errors.append(
1525 checks.Error(
1526 "Field defines a relation to the CompositePrimaryKey of model "
1527 f"{self.remote_field.model._meta.object_name!r} which is not "
1528 "supported.",
1529 obj=self,
1530 id="fields.E347",
1531 )
1532 )
1533 relationship_model_name = self.remote_field.through._meta.object_name
1534 self_referential = from_model == to_model
1535 # Count foreign keys in intermediate model
1536 if self_referential:
1537 seen_self = sum(
1538 from_model == getattr(field.remote_field, "model", None)
1539 for field in self.remote_field.through._meta.fields
1540 )
1541
1542 if seen_self > 2 and not self.remote_field.through_fields:
1543 errors.append(
1544 checks.Error(
1545 "The model is used as an intermediate model by "
1546 "'%s', but it has more than two foreign keys "
1547 "to '%s', which is ambiguous. You must specify "
1548 "which two foreign keys Django should use via the "
1549 "through_fields keyword argument."
1550 % (self, from_model_name),
1551 hint=(
1552 "Use through_fields to specify which two foreign keys "
1553 "Django should use."
1554 ),
1555 obj=self.remote_field.through,
1556 id="fields.E333",
1557 )
1558 )
1559
1560 else:
1561 # Count foreign keys in relationship model
1562 seen_from = sum(
1563 from_model == getattr(field.remote_field, "model", None)
1564 for field in self.remote_field.through._meta.fields
1565 )
1566 seen_to = sum(
1567 to_model == getattr(field.remote_field, "model", None)
1568 for field in self.remote_field.through._meta.fields
1569 )
1570
1571 if seen_from > 1 and not self.remote_field.through_fields:
1572 errors.append(
1573 checks.Error(
1574 (
1575 "The model is used as an intermediate model by "
1576 "'%s', but it has more than one foreign key "
1577 "from '%s', which is ambiguous. You must specify "
1578 "which foreign key Django should use via the "
1579 "through_fields keyword argument."
1580 )
1581 % (self, from_model_name),
1582 hint=(
1583 "If you want to create a recursive relationship, "
1584 'use ManyToManyField("%s", through="%s").'
1585 )
1586 % (
1587 RECURSIVE_RELATIONSHIP_CONSTANT,
1588 relationship_model_name,
1589 ),
1590 obj=self,
1591 id="fields.E334",
1592 )
1593 )
1594
1595 if seen_to > 1 and not self.remote_field.through_fields:
1596 errors.append(
1597 checks.Error(
1598 "The model is used as an intermediate model by "
1599 "'%s', but it has more than one foreign key "
1600 "to '%s', which is ambiguous. You must specify "
1601 "which foreign key Django should use via the "
1602 "through_fields keyword argument." % (self, to_model_name),
1603 hint=(
1604 "If you want to create a recursive relationship, "
1605 'use ManyToManyField("%s", through="%s").'
1606 )
1607 % (
1608 RECURSIVE_RELATIONSHIP_CONSTANT,
1609 relationship_model_name,
1610 ),
1611 obj=self,
1612 id="fields.E335",
1613 )
1614 )
1615
1616 if seen_from == 0 or seen_to == 0:
1617 errors.append(
1618 checks.Error(
1619 "The model is used as an intermediate model by "
1620 "'%s', but it does not have a foreign key to '%s' or '%s'."
1621 % (self, from_model_name, to_model_name),
1622 obj=self.remote_field.through,
1623 id="fields.E336",
1624 )
1625 )
1626
1627 # Validate `through_fields`.
1628 if self.remote_field.through_fields is not None:
1629 # Validate that we're given an iterable of at least two items
1630 # and that none of them is "falsy".
1631 if not (
1632 len(self.remote_field.through_fields) >= 2
1633 and self.remote_field.through_fields[0]
1634 and self.remote_field.through_fields[1]
1635 ):
1636 errors.append(
1637 checks.Error(
1638 "Field specifies 'through_fields' but does not provide "
1639 "the names of the two link fields that should be used "
1640 "for the relation through model '%s'." % qualified_model_name,
1641 hint=(
1642 "Make sure you specify 'through_fields' as "
1643 "through_fields=('field1', 'field2')"
1644 ),
1645 obj=self,
1646 id="fields.E337",
1647 )
1648 )
1649
1650 # Validate the given through fields -- they should be actual
1651 # fields on the through model, and also be foreign keys to the
1652 # expected models.
1653 else:
1654 assert from_model is not None, (
1655 "ManyToManyField with intermediate "
1656 "tables cannot be checked if you don't pass the model "
1657 "where the field is attached to."
1658 )
1659
1660 source, through, target = (
1661 from_model,
1662 self.remote_field.through,
1663 self.remote_field.model,
1664 )
1665 source_field_name, target_field_name = self.remote_field.through_fields[
1666 :2
1667 ]
1668
1669 for field_name, related_model in (
1670 (source_field_name, source),
1671 (target_field_name, target),
1672 ):
1673 possible_field_names = []
1674 for f in through._meta.fields:
1675 if (
1676 hasattr(f, "remote_field")
1677 and getattr(f.remote_field, "model", None) == related_model
1678 ):
1679 possible_field_names.append(f.name)
1680 if possible_field_names:
1681 hint = (
1682 "Did you mean one of the following foreign keys to '%s': "
1683 "%s?"
1684 % (
1685 related_model._meta.object_name,
1686 ", ".join(possible_field_names),
1687 )
1688 )
1689 else:
1690 hint = None
1691
1692 try:
1693 field = through._meta.get_field(field_name)
1694 except exceptions.FieldDoesNotExist:
1695 errors.append(
1696 checks.Error(
1697 "The intermediary model '%s' has no field '%s'."
1698 % (qualified_model_name, field_name),
1699 hint=hint,
1700 obj=self,
1701 id="fields.E338",
1702 )
1703 )
1704 else:
1705 if not (
1706 hasattr(field, "remote_field")
1707 and getattr(field.remote_field, "model", None)
1708 == related_model
1709 ):
1710 errors.append(
1711 checks.Error(
1712 "'%s.%s' is not a foreign key to '%s'."
1713 % (
1714 through._meta.object_name,
1715 field_name,
1716 related_model._meta.object_name,
1717 ),
1718 hint=hint,
1719 obj=self,
1720 id="fields.E339",
1721 )
1722 )
1723
1724 return errors
1725
1726 def _check_table_uniqueness(self, **kwargs):
1727 if (
1728 isinstance(self.remote_field.through, str)
1729 or not self.remote_field.through._meta.managed
1730 ):
1731 return []
1732 registered_tables = {
1733 model._meta.db_table: model
1734 for model in self.opts.apps.get_models(include_auto_created=True)
1735 if model != self.remote_field.through and model._meta.managed
1736 }
1737 m2m_db_table = self.m2m_db_table()
1738 model = registered_tables.get(m2m_db_table)
1739 # The second condition allows multiple m2m relations on a model if
1740 # some point to a through model that proxies another through model.
1741 if (
1742 model
1743 and model._meta.concrete_model
1744 != self.remote_field.through._meta.concrete_model
1745 ):
1746 if model._meta.auto_created:
1747
1748 def _get_field_name(model):
1749 for field in model._meta.auto_created._meta.many_to_many:
1750 if field.remote_field.through is model:
1751 return field.name
1752
1753 opts = model._meta.auto_created._meta
1754 clashing_obj = "%s.%s" % (opts.label, _get_field_name(model))
1755 else:
1756 clashing_obj = model._meta.label
1757 if settings.DATABASE_ROUTERS:
1758 error_class, error_id = checks.Warning, "fields.W344"
1759 error_hint = (
1760 "You have configured settings.DATABASE_ROUTERS. Verify "
1761 "that the table of %r is correctly routed to a separate "
1762 "database." % clashing_obj
1763 )
1764 else:
1765 error_class, error_id = checks.Error, "fields.E340"
1766 error_hint = None
1767 return [
1768 error_class(
1769 "The field's intermediary table '%s' clashes with the "
1770 "table name of '%s'." % (m2m_db_table, clashing_obj),
1771 obj=self,
1772 hint=error_hint,
1773 id=error_id,
1774 )
1775 ]
1776 return []
1777
1778 def deconstruct(self):
1779 name, path, args, kwargs = super().deconstruct()
1780 # Handle the simpler arguments.
1781 if self.db_table is not None:
1782 kwargs["db_table"] = self.db_table
1783 if self.remote_field.db_constraint is not True:
1784 kwargs["db_constraint"] = self.remote_field.db_constraint
1785 # Lowercase model names as they should be treated as case-insensitive.
1786 if isinstance(self.remote_field.model, str):
1787 if "." in self.remote_field.model:
1788 app_label, model_name = self.remote_field.model.split(".")
1789 kwargs["to"] = "%s.%s" % (app_label, model_name.lower())
1790 else:
1791 kwargs["to"] = self.remote_field.model.lower()
1792 else:
1793 kwargs["to"] = self.remote_field.model._meta.label_lower
1794 if getattr(self.remote_field, "through", None) is not None:
1795 if isinstance(self.remote_field.through, str):
1796 kwargs["through"] = self.remote_field.through
1797 elif not self.remote_field.through._meta.auto_created:
1798 kwargs["through"] = self.remote_field.through._meta.label
1799 # If swappable is True, then see if we're actually pointing to the target
1800 # of a swap.
1801 swappable_setting = self.swappable_setting
1802 if swappable_setting is not None:
1803 # If it's already a settings reference, error.
1804 if hasattr(kwargs["to"], "setting_name"):
1805 if kwargs["to"].setting_name != swappable_setting:
1806 raise ValueError(
1807 "Cannot deconstruct a ManyToManyField pointing to a "
1808 "model that is swapped in place of more than one model "
1809 "(%s and %s)" % (kwargs["to"].setting_name, swappable_setting)
1810 )
1811
1812 kwargs["to"] = SettingsReference(
1813 kwargs["to"],
1814 swappable_setting,
1815 )
1816 return name, path, args, kwargs
1817
1818 def _get_path_info(self, direct=False, filtered_relation=None):
1819 """Called by both direct and indirect m2m traversal."""
1820 int_model = self.remote_field.through
1821 linkfield1 = int_model._meta.get_field(self.m2m_field_name())
1822 linkfield2 = int_model._meta.get_field(self.m2m_reverse_field_name())
1823 if direct:
1824 join1infos = linkfield1.reverse_path_infos
1825 if filtered_relation:
1826 join2infos = linkfield2.get_path_info(filtered_relation)
1827 else:
1828 join2infos = linkfield2.path_infos
1829 else:
1830 join1infos = linkfield2.reverse_path_infos
1831 if filtered_relation:
1832 join2infos = linkfield1.get_path_info(filtered_relation)
1833 else:
1834 join2infos = linkfield1.path_infos
1835 # Get join infos between the last model of join 1 and the first model
1836 # of join 2. Assume the only reason these may differ is due to model
1837 # inheritance.
1838 join1_final = join1infos[-1].to_opts
1839 join2_initial = join2infos[0].from_opts
1840 if join1_final is join2_initial:
1841 intermediate_infos = []
1842 elif issubclass(join1_final.model, join2_initial.model):
1843 intermediate_infos = join1_final.get_path_to_parent(join2_initial.model)
1844 else:
1845 intermediate_infos = join2_initial.get_path_from_parent(join1_final.model)
1846
1847 return [*join1infos, *intermediate_infos, *join2infos]
1848
1849 def get_path_info(self, filtered_relation=None):
1850 return self._get_path_info(direct=True, filtered_relation=filtered_relation)
1851
1852 @cached_property
1853 def path_infos(self):
1854 return self.get_path_info()
1855
1856 def get_reverse_path_info(self, filtered_relation=None):
1857 return self._get_path_info(direct=False, filtered_relation=filtered_relation)
1858
1859 @cached_property
1860 def reverse_path_infos(self):
1861 return self.get_reverse_path_info()
1862
1863 def _get_m2m_db_table(self, opts):
1864 """
1865 Function that can be curried to provide the m2m table name for this
1866 relation.
1867 """
1868 if self.remote_field.through is not None:
1869 return self.remote_field.through._meta.db_table
1870 elif self.db_table:
1871 return self.db_table
1872 else:
1873 m2m_table_name = "%s_%s" % (utils.strip_quotes(opts.db_table), self.name)
1874 return utils.truncate_name(m2m_table_name, connection.ops.max_name_length())
1875
1876 def _get_m2m_attr(self, related, attr):
1877 """
1878 Function that can be curried to provide the source accessor or DB
1879 column name for the m2m table.
1880 """
1881 cache_attr = "_m2m_%s_cache" % attr
1882 if hasattr(self, cache_attr):
1883 return getattr(self, cache_attr)
1884 if self.remote_field.through_fields is not None:
1885 link_field_name = self.remote_field.through_fields[0]
1886 else:
1887 link_field_name = None
1888 for f in self.remote_field.through._meta.fields:
1889 if (
1890 f.is_relation
1891 and f.remote_field.model == related.related_model
1892 and (link_field_name is None or link_field_name == f.name)
1893 ):
1894 setattr(self, cache_attr, getattr(f, attr))
1895 return getattr(self, cache_attr)
1896
1897 def _get_m2m_reverse_attr(self, related, attr):
1898 """
1899 Function that can be curried to provide the related accessor or DB
1900 column name for the m2m table.
1901 """
1902 cache_attr = "_m2m_reverse_%s_cache" % attr
1903 if hasattr(self, cache_attr):
1904 return getattr(self, cache_attr)
1905 found = False
1906 if self.remote_field.through_fields is not None:
1907 link_field_name = self.remote_field.through_fields[1]
1908 else:
1909 link_field_name = None
1910 for f in self.remote_field.through._meta.fields:
1911 if f.is_relation and f.remote_field.model == related.model:
1912 if link_field_name is None and related.related_model == related.model:
1913 # If this is an m2m-intermediate to self,
1914 # the first foreign key you find will be
1915 # the source column. Keep searching for
1916 # the second foreign key.
1917 if found:
1918 setattr(self, cache_attr, getattr(f, attr))
1919 break
1920 else:
1921 found = True
1922 elif link_field_name is None or link_field_name == f.name:
1923 setattr(self, cache_attr, getattr(f, attr))
1924 break
1925 return getattr(self, cache_attr)
1926
1927 def contribute_to_class(self, cls, name, **kwargs):
1928 # To support multiple relations to self, it's useful to have a non-None
1929 # related name on symmetrical relations for internal reasons. The
1930 # concept doesn't make a lot of sense externally ("you want me to
1931 # specify *what* on my non-reversible relation?!"), so we set it up
1932 # automatically. The funky name reduces the chance of an accidental
1933 # clash.
1934 if self.remote_field.symmetrical and (
1935 self.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT
1936 or self.remote_field.model == cls._meta.object_name
1937 ):
1938 self.remote_field.related_name = "%s_rel_+" % name
1939 elif self.remote_field.hidden:
1940 # If the backwards relation is disabled, replace the original
1941 # related_name with one generated from the m2m field name. Django
1942 # still uses backwards relations internally and we need to avoid
1943 # clashes between multiple m2m fields with related_name == '+'.
1944 self.remote_field.related_name = "_%s_%s_%s_+" % (
1945 cls._meta.app_label,
1946 cls.__name__.lower(),
1947 name,
1948 )
1949
1950 super().contribute_to_class(cls, name, **kwargs)
1951
1952 # The intermediate m2m model is not auto created if:
1953 # 1) There is a manually specified intermediate, or
1954 # 2) The class owning the m2m field is abstract.
1955 # 3) The class owning the m2m field has been swapped out.
1956 if not cls._meta.abstract:
1957 if self.remote_field.through:
1958
1959 def resolve_through_model(_, model, field):
1960 field.remote_field.through = model
1961
1962 lazy_related_operation(
1963 resolve_through_model, cls, self.remote_field.through, field=self
1964 )
1965 elif not cls._meta.swapped:
1966 self.remote_field.through = create_many_to_many_intermediary_model(
1967 self, cls
1968 )
1969
1970 # Add the descriptor for the m2m relation.
1971 setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False))
1972
1973 # Set up the accessor for the m2m table name for the relation.
1974 self.m2m_db_table = partial(self._get_m2m_db_table, cls._meta)
1975
1976 def contribute_to_related_class(self, cls, related):
1977 # Internal M2Ms (i.e., those with a related name ending with '+')
1978 # and swapped models don't get a related descriptor.
1979 if not self.remote_field.hidden and not related.related_model._meta.swapped:
1980 setattr(
1981 cls,
1982 related.accessor_name,
1983 ManyToManyDescriptor(self.remote_field, reverse=True),
1984 )
1985
1986 # Set up the accessors for the column names on the m2m table.
1987 self.m2m_column_name = partial(self._get_m2m_attr, related, "column")
1988 self.m2m_reverse_name = partial(self._get_m2m_reverse_attr, related, "column")
1989
1990 self.m2m_field_name = partial(self._get_m2m_attr, related, "name")
1991 self.m2m_reverse_field_name = partial(
1992 self._get_m2m_reverse_attr, related, "name"
1993 )
1994
1995 get_m2m_rel = partial(self._get_m2m_attr, related, "remote_field")
1996 self.m2m_target_field_name = lambda: get_m2m_rel().field_name
1997 get_m2m_reverse_rel = partial(
1998 self._get_m2m_reverse_attr, related, "remote_field"
1999 )
2000 self.m2m_reverse_target_field_name = lambda: get_m2m_reverse_rel().field_name
2001
2002 def set_attributes_from_rel(self):
2003 pass
2004
2005 def value_from_object(self, obj):
2006 return list(getattr(obj, self.attname).all()) if obj._is_pk_set() else []
2007
2008 def save_form_data(self, instance, data):
2009 getattr(instance, self.attname).set(data)
2010
2011 def formfield(self, *, using=None, **kwargs):
2012 defaults = {
2013 "form_class": forms.ModelMultipleChoiceField,
2014 "queryset": self.remote_field.model._default_manager.using(using),
2015 **kwargs,
2016 }
2017 # If initial is passed in, it's a list of related objects, but the
2018 # MultipleChoiceField takes a list of IDs.
2019 if defaults.get("initial") is not None:
2020 initial = defaults["initial"]
2021 if callable(initial):
2022 initial = initial()
2023 defaults["initial"] = [i.pk for i in initial]
2024 return super().formfield(**defaults)
2025
2026 def db_check(self, connection):
2027 return None
2028
2029 def db_type(self, connection):
2030 # A ManyToManyField is not represented by a single column,
2031 # so return None.
2032 return None
2033
2034 def db_parameters(self, connection):
2035 return {"type": None, "check": None}