1"""
2Accessors for related objects.
3
4When a field defines a relation between two models, each model class provides
5an attribute to access related instances of the other model class (unless the
6reverse accessor has been disabled with related_name='+').
7
8Accessors are implemented as descriptors in order to customize access and
9assignment. This module defines the descriptor classes.
10
11Forward accessors follow foreign keys. Reverse accessors trace them back. For
12example, with the following models::
13
14 class Parent(Model):
15 pass
16
17 class Child(Model):
18 parent = ForeignKey(Parent, related_name='children')
19
20 ``child.parent`` is a forward many-to-one relation. ``parent.children`` is a
21reverse many-to-one relation.
22
23There are three types of relations (many-to-one, one-to-one, and many-to-many)
24and two directions (forward and reverse) for a total of six combinations.
25
261. Related instance on the forward side of a many-to-one relation:
27 ``ForwardManyToOneDescriptor``.
28
29 Uniqueness of foreign key values is irrelevant to accessing the related
30 instance, making the many-to-one and one-to-one cases identical as far as
31 the descriptor is concerned. The constraint is checked upstream (unicity
32 validation in forms) or downstream (unique indexes in the database).
33
342. Related instance on the forward side of a one-to-one
35 relation: ``ForwardOneToOneDescriptor``.
36
37 It avoids querying the database when accessing the parent link field in
38 a multi-table inheritance scenario.
39
403. Related instance on the reverse side of a one-to-one relation:
41 ``ReverseOneToOneDescriptor``.
42
43 One-to-one relations are asymmetrical, despite the apparent symmetry of the
44 name, because they're implemented in the database with a foreign key from
45 one table to another. As a consequence ``ReverseOneToOneDescriptor`` is
46 slightly different from ``ForwardManyToOneDescriptor``.
47
484. Related objects manager for related instances on the reverse side of a
49 many-to-one relation: ``ReverseManyToOneDescriptor``.
50
51 Unlike the previous two classes, this one provides access to a collection
52 of objects. It returns a manager rather than an instance.
53
545. Related objects manager for related instances on the forward or reverse
55 sides of a many-to-many relation: ``ManyToManyDescriptor``.
56
57 Many-to-many relations are symmetrical. The syntax of Django models
58 requires declaring them on one side but that's an implementation detail.
59 They could be declared on the other side without any change in behavior.
60 Therefore the forward and reverse descriptors can be the same.
61
62 If you're looking for ``ForwardManyToManyDescriptor`` or
63 ``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead.
64"""
65
66from asgiref.sync import sync_to_async
67
68from django.core.exceptions import FieldError
69from django.db import (
70 DEFAULT_DB_ALIAS,
71 NotSupportedError,
72 connections,
73 router,
74 transaction,
75)
76from django.db.models import Manager, Q, Window, signals
77from django.db.models.functions import RowNumber
78from django.db.models.lookups import GreaterThan, LessThanOrEqual
79from django.db.models.query import QuerySet
80from django.db.models.query_utils import DeferredAttribute
81from django.db.models.utils import AltersData, resolve_callables
82from django.utils.functional import cached_property
83
84
85class ForeignKeyDeferredAttribute(DeferredAttribute):
86 def __set__(self, instance, value):
87 if instance.__dict__.get(self.field.attname) != value and self.field.is_cached(
88 instance
89 ):
90 self.field.delete_cached_value(instance)
91 instance.__dict__[self.field.attname] = value
92
93
94def _filter_prefetch_queryset(queryset, field_name, instances):
95 predicate = Q(**{f"{field_name}__in": instances})
96 db = queryset._db or DEFAULT_DB_ALIAS
97 if queryset.query.is_sliced:
98 if not connections[db].features.supports_over_clause:
99 raise NotSupportedError(
100 "Prefetching from a limited queryset is only supported on backends "
101 "that support window functions."
102 )
103 low_mark, high_mark = queryset.query.low_mark, queryset.query.high_mark
104 order_by = [
105 expr for expr, _ in queryset.query.get_compiler(using=db).get_order_by()
106 ]
107 window = Window(RowNumber(), partition_by=field_name, order_by=order_by)
108 predicate &= GreaterThan(window, low_mark)
109 if high_mark is not None:
110 predicate &= LessThanOrEqual(window, high_mark)
111 queryset.query.clear_limits()
112 return queryset.filter(predicate)
113
114
115class ForwardManyToOneDescriptor:
116 """
117 Accessor to the related object on the forward side of a many-to-one or
118 one-to-one (via ForwardOneToOneDescriptor subclass) relation.
119
120 In the example::
121
122 class Child(Model):
123 parent = ForeignKey(Parent, related_name='children')
124
125 ``Child.parent`` is a ``ForwardManyToOneDescriptor`` instance.
126 """
127
128 def __init__(self, field_with_rel):
129 self.field = field_with_rel
130
131 @cached_property
132 def RelatedObjectDoesNotExist(self):
133 # The exception can't be created at initialization time since the
134 # related model might not be resolved yet; `self.field.model` might
135 # still be a string model reference.
136 return type(
137 "RelatedObjectDoesNotExist",
138 (self.field.remote_field.model.DoesNotExist, AttributeError),
139 {
140 "__module__": self.field.model.__module__,
141 "__qualname__": "%s.%s.RelatedObjectDoesNotExist"
142 % (
143 self.field.model.__qualname__,
144 self.field.name,
145 ),
146 },
147 )
148
149 def is_cached(self, instance):
150 return self.field.is_cached(instance)
151
152 def get_queryset(self, **hints):
153 return self.field.remote_field.model._base_manager.db_manager(hints=hints).all()
154
155 def get_prefetch_querysets(self, instances, querysets=None):
156 if querysets and len(querysets) != 1:
157 raise ValueError(
158 "querysets argument of get_prefetch_querysets() should have a length "
159 "of 1."
160 )
161 queryset = querysets[0] if querysets else self.get_queryset()
162 queryset._add_hints(instance=instances[0])
163
164 rel_obj_attr = self.field.get_foreign_related_value
165 instance_attr = self.field.get_local_related_value
166 instances_dict = {instance_attr(inst): inst for inst in instances}
167 related_field = self.field.foreign_related_fields[0]
168 remote_field = self.field.remote_field
169
170 # FIXME: This will need to be revisited when we introduce support for
171 # composite fields. In the meantime we take this practical approach to
172 # solve a regression on 1.6 when the reverse manager is hidden
173 # (related_name ends with a '+'). Refs #21410.
174 # The check for len(...) == 1 is a special case that allows the query
175 # to be join-less and smaller. Refs #21760.
176 if remote_field.hidden or len(self.field.foreign_related_fields) == 1:
177 query = {
178 "%s__in"
179 % related_field.name: {instance_attr(inst)[0] for inst in instances}
180 }
181 else:
182 query = {"%s__in" % self.field.related_query_name(): instances}
183 queryset = queryset.filter(**query)
184 # There can be only one object prefetched for each instance so clear
185 # ordering if the query allows it without side effects.
186 queryset.query.clear_ordering()
187
188 # Since we're going to assign directly in the cache,
189 # we must manage the reverse relation cache manually.
190 if not remote_field.multiple:
191 for rel_obj in queryset:
192 instance = instances_dict[rel_obj_attr(rel_obj)]
193 remote_field.set_cached_value(rel_obj, instance)
194 return (
195 queryset,
196 rel_obj_attr,
197 instance_attr,
198 True,
199 self.field.cache_name,
200 False,
201 )
202
203 def get_object(self, instance):
204 qs = self.get_queryset(instance=instance)
205 # Assuming the database enforces foreign keys, this won't fail.
206 return qs.get(self.field.get_reverse_related_filter(instance))
207
208 def __get__(self, instance, cls=None):
209 """
210 Get the related instance through the forward relation.
211
212 With the example above, when getting ``child.parent``:
213
214 - ``self`` is the descriptor managing the ``parent`` attribute
215 - ``instance`` is the ``child`` instance
216 - ``cls`` is the ``Child`` class (we don't need it)
217 """
218 if instance is None:
219 return self
220
221 # The related instance is loaded from the database and then cached
222 # by the field on the model instance state. It can also be pre-cached
223 # by the reverse accessor (ReverseOneToOneDescriptor).
224 try:
225 rel_obj = self.field.get_cached_value(instance)
226 except KeyError:
227 has_value = None not in self.field.get_local_related_value(instance)
228 ancestor_link = (
229 instance._meta.get_ancestor_link(self.field.model)
230 if has_value
231 else None
232 )
233 if ancestor_link and ancestor_link.is_cached(instance):
234 # An ancestor link will exist if this field is defined on a
235 # multi-table inheritance parent of the instance's class.
236 ancestor = ancestor_link.get_cached_value(instance)
237 # The value might be cached on an ancestor if the instance
238 # originated from walking down the inheritance chain.
239 rel_obj = self.field.get_cached_value(ancestor, default=None)
240 else:
241 rel_obj = None
242 if rel_obj is None and has_value:
243 rel_obj = self.get_object(instance)
244 remote_field = self.field.remote_field
245 # If this is a one-to-one relation, set the reverse accessor
246 # cache on the related object to the current instance to avoid
247 # an extra SQL query if it's accessed later on.
248 if not remote_field.multiple:
249 remote_field.set_cached_value(rel_obj, instance)
250 self.field.set_cached_value(instance, rel_obj)
251
252 if rel_obj is None and not self.field.null:
253 raise self.RelatedObjectDoesNotExist(
254 "%s has no %s." % (self.field.model.__name__, self.field.name)
255 )
256 else:
257 return rel_obj
258
259 def __set__(self, instance, value):
260 """
261 Set the related instance through the forward relation.
262
263 With the example above, when setting ``child.parent = parent``:
264
265 - ``self`` is the descriptor managing the ``parent`` attribute
266 - ``instance`` is the ``child`` instance
267 - ``value`` is the ``parent`` instance on the right of the equal sign
268 """
269 # An object must be an instance of the related class.
270 if value is not None and not isinstance(
271 value, self.field.remote_field.model._meta.concrete_model
272 ):
273 raise ValueError(
274 'Cannot assign "%r": "%s.%s" must be a "%s" instance.'
275 % (
276 value,
277 instance._meta.object_name,
278 self.field.name,
279 self.field.remote_field.model._meta.object_name,
280 )
281 )
282 elif value is not None:
283 if instance._state.db is None:
284 instance._state.db = router.db_for_write(
285 instance.__class__, instance=value
286 )
287 if value._state.db is None:
288 value._state.db = router.db_for_write(
289 value.__class__, instance=instance
290 )
291 if not router.allow_relation(value, instance):
292 raise ValueError(
293 'Cannot assign "%r": the current database router prevents this '
294 "relation." % value
295 )
296
297 remote_field = self.field.remote_field
298 # If we're setting the value of a OneToOneField to None, we need to clear
299 # out the cache on any old related object. Otherwise, deleting the
300 # previously-related object will also cause this object to be deleted,
301 # which is wrong.
302 if value is None:
303 # Look up the previously-related object, which may still be available
304 # since we've not yet cleared out the related field.
305 # Use the cache directly, instead of the accessor; if we haven't
306 # populated the cache, then we don't care - we're only accessing
307 # the object to invalidate the accessor cache, so there's no
308 # need to populate the cache just to expire it again.
309 related = self.field.get_cached_value(instance, default=None)
310
311 # If we've got an old related object, we need to clear out its
312 # cache. This cache also might not exist if the related object
313 # hasn't been accessed yet.
314 if related is not None:
315 remote_field.set_cached_value(related, None)
316
317 for lh_field, rh_field in self.field.related_fields:
318 setattr(instance, lh_field.attname, None)
319
320 # Set the values of the related field.
321 else:
322 for lh_field, rh_field in self.field.related_fields:
323 setattr(instance, lh_field.attname, getattr(value, rh_field.attname))
324
325 # Set the related instance cache used by __get__ to avoid an SQL query
326 # when accessing the attribute we just set.
327 self.field.set_cached_value(instance, value)
328
329 # If this is a one-to-one relation, set the reverse accessor cache on
330 # the related object to the current instance to avoid an extra SQL
331 # query if it's accessed later on.
332 if value is not None and not remote_field.multiple:
333 remote_field.set_cached_value(value, instance)
334
335 def __reduce__(self):
336 """
337 Pickling should return the instance attached by self.field on the
338 model, not a new copy of that descriptor. Use getattr() to retrieve
339 the instance directly from the model.
340 """
341 return getattr, (self.field.model, self.field.name)
342
343
344class ForwardOneToOneDescriptor(ForwardManyToOneDescriptor):
345 """
346 Accessor to the related object on the forward side of a one-to-one relation.
347
348 In the example::
349
350 class Restaurant(Model):
351 place = OneToOneField(Place, related_name='restaurant')
352
353 ``Restaurant.place`` is a ``ForwardOneToOneDescriptor`` instance.
354 """
355
356 def get_object(self, instance):
357 if self.field.remote_field.parent_link:
358 deferred = instance.get_deferred_fields()
359 # Because it's a parent link, all the data is available in the
360 # instance, so populate the parent model with this data.
361 rel_model = self.field.remote_field.model
362 fields = [field.attname for field in rel_model._meta.concrete_fields]
363
364 # If any of the related model's fields are deferred, fallback to
365 # fetching all fields from the related model. This avoids a query
366 # on the related model for every deferred field.
367 if not any(field in fields for field in deferred):
368 kwargs = {field: getattr(instance, field) for field in fields}
369 obj = rel_model(**kwargs)
370 obj._state.adding = instance._state.adding
371 obj._state.db = instance._state.db
372 return obj
373 return super().get_object(instance)
374
375 def __set__(self, instance, value):
376 super().__set__(instance, value)
377 # If the primary key is a link to a parent model and a parent instance
378 # is being set, update the value of the inherited pk(s).
379 if self.field.primary_key and self.field.remote_field.parent_link:
380 opts = instance._meta
381 # Inherited primary key fields from this object's base classes.
382 inherited_pk_fields = [
383 field
384 for field in opts.concrete_fields
385 if field.primary_key and field.remote_field
386 ]
387 for field in inherited_pk_fields:
388 rel_model_pk_name = field.remote_field.model._meta.pk.attname
389 raw_value = (
390 getattr(value, rel_model_pk_name) if value is not None else None
391 )
392 setattr(instance, rel_model_pk_name, raw_value)
393
394
395class ReverseOneToOneDescriptor:
396 """
397 Accessor to the related object on the reverse side of a one-to-one
398 relation.
399
400 In the example::
401
402 class Restaurant(Model):
403 place = OneToOneField(Place, related_name='restaurant')
404
405 ``Place.restaurant`` is a ``ReverseOneToOneDescriptor`` instance.
406 """
407
408 def __init__(self, related):
409 # Following the example above, `related` is an instance of OneToOneRel
410 # which represents the reverse restaurant field (place.restaurant).
411 self.related = related
412
413 @cached_property
414 def RelatedObjectDoesNotExist(self):
415 # The exception isn't created at initialization time for the sake of
416 # consistency with `ForwardManyToOneDescriptor`.
417 return type(
418 "RelatedObjectDoesNotExist",
419 (self.related.related_model.DoesNotExist, AttributeError),
420 {
421 "__module__": self.related.model.__module__,
422 "__qualname__": "%s.%s.RelatedObjectDoesNotExist"
423 % (
424 self.related.model.__qualname__,
425 self.related.name,
426 ),
427 },
428 )
429
430 def is_cached(self, instance):
431 return self.related.is_cached(instance)
432
433 def get_queryset(self, **hints):
434 return self.related.related_model._base_manager.db_manager(hints=hints).all()
435
436 def get_prefetch_querysets(self, instances, querysets=None):
437 if querysets and len(querysets) != 1:
438 raise ValueError(
439 "querysets argument of get_prefetch_querysets() should have a length "
440 "of 1."
441 )
442 queryset = querysets[0] if querysets else self.get_queryset()
443 queryset._add_hints(instance=instances[0])
444
445 rel_obj_attr = self.related.field.get_local_related_value
446 instance_attr = self.related.field.get_foreign_related_value
447 instances_dict = {instance_attr(inst): inst for inst in instances}
448 query = {"%s__in" % self.related.field.name: instances}
449 queryset = queryset.filter(**query)
450 # There can be only one object prefetched for each instance so clear
451 # ordering if the query allows it without side effects.
452 queryset.query.clear_ordering()
453
454 # Since we're going to assign directly in the cache,
455 # we must manage the reverse relation cache manually.
456 for rel_obj in queryset:
457 instance = instances_dict[rel_obj_attr(rel_obj)]
458 self.related.field.set_cached_value(rel_obj, instance)
459 return (
460 queryset,
461 rel_obj_attr,
462 instance_attr,
463 True,
464 self.related.cache_name,
465 False,
466 )
467
468 def __get__(self, instance, cls=None):
469 """
470 Get the related instance through the reverse relation.
471
472 With the example above, when getting ``place.restaurant``:
473
474 - ``self`` is the descriptor managing the ``restaurant`` attribute
475 - ``instance`` is the ``place`` instance
476 - ``cls`` is the ``Place`` class (unused)
477
478 Keep in mind that ``Restaurant`` holds the foreign key to ``Place``.
479 """
480 if instance is None:
481 return self
482
483 # The related instance is loaded from the database and then cached
484 # by the field on the model instance state. It can also be pre-cached
485 # by the forward accessor (ForwardManyToOneDescriptor).
486 try:
487 rel_obj = self.related.get_cached_value(instance)
488 except KeyError:
489 if not instance._is_pk_set():
490 rel_obj = None
491 else:
492 filter_args = self.related.field.get_forward_related_filter(instance)
493 try:
494 rel_obj = self.get_queryset(instance=instance).get(**filter_args)
495 except self.related.related_model.DoesNotExist:
496 rel_obj = None
497 else:
498 # Set the forward accessor cache on the related object to
499 # the current instance to avoid an extra SQL query if it's
500 # accessed later on.
501 self.related.field.set_cached_value(rel_obj, instance)
502 self.related.set_cached_value(instance, rel_obj)
503
504 if rel_obj is None:
505 raise self.RelatedObjectDoesNotExist(
506 "%s has no %s."
507 % (instance.__class__.__name__, self.related.accessor_name)
508 )
509 else:
510 return rel_obj
511
512 def __set__(self, instance, value):
513 """
514 Set the related instance through the reverse relation.
515
516 With the example above, when setting ``place.restaurant = restaurant``:
517
518 - ``self`` is the descriptor managing the ``restaurant`` attribute
519 - ``instance`` is the ``place`` instance
520 - ``value`` is the ``restaurant`` instance on the right of the equal sign
521
522 Keep in mind that ``Restaurant`` holds the foreign key to ``Place``.
523 """
524 # The similarity of the code below to the code in
525 # ForwardManyToOneDescriptor is annoying, but there's a bunch
526 # of small differences that would make a common base class convoluted.
527
528 if value is None:
529 # Update the cached related instance (if any) & clear the cache.
530 # Following the example above, this would be the cached
531 # ``restaurant`` instance (if any).
532 rel_obj = self.related.get_cached_value(instance, default=None)
533 if rel_obj is not None:
534 # Remove the ``restaurant`` instance from the ``place``
535 # instance cache.
536 self.related.delete_cached_value(instance)
537 # Set the ``place`` field on the ``restaurant``
538 # instance to None.
539 setattr(rel_obj, self.related.field.name, None)
540 elif not isinstance(value, self.related.related_model):
541 # An object must be an instance of the related class.
542 raise ValueError(
543 'Cannot assign "%r": "%s.%s" must be a "%s" instance.'
544 % (
545 value,
546 instance._meta.object_name,
547 self.related.accessor_name,
548 self.related.related_model._meta.object_name,
549 )
550 )
551 else:
552 if instance._state.db is None:
553 instance._state.db = router.db_for_write(
554 instance.__class__, instance=value
555 )
556 if value._state.db is None:
557 value._state.db = router.db_for_write(
558 value.__class__, instance=instance
559 )
560 if not router.allow_relation(value, instance):
561 raise ValueError(
562 'Cannot assign "%r": the current database router prevents this '
563 "relation." % value
564 )
565
566 related_pk = tuple(
567 getattr(instance, field.attname)
568 for field in self.related.field.foreign_related_fields
569 )
570 # Set the value of the related field to the value of the related
571 # object's related field.
572 for index, field in enumerate(self.related.field.local_related_fields):
573 setattr(value, field.attname, related_pk[index])
574
575 # Set the related instance cache used by __get__ to avoid an SQL query
576 # when accessing the attribute we just set.
577 self.related.set_cached_value(instance, value)
578
579 # Set the forward accessor cache on the related object to the current
580 # instance to avoid an extra SQL query if it's accessed later on.
581 self.related.field.set_cached_value(value, instance)
582
583 def __reduce__(self):
584 # Same purpose as ForwardManyToOneDescriptor.__reduce__().
585 return getattr, (self.related.model, self.related.name)
586
587
588class ReverseManyToOneDescriptor:
589 """
590 Accessor to the related objects manager on the reverse side of a
591 many-to-one relation.
592
593 In the example::
594
595 class Child(Model):
596 parent = ForeignKey(Parent, related_name='children')
597
598 ``Parent.children`` is a ``ReverseManyToOneDescriptor`` instance.
599
600 Most of the implementation is delegated to a dynamically defined manager
601 class built by ``create_forward_many_to_many_manager()`` defined below.
602 """
603
604 def __init__(self, rel):
605 self.rel = rel
606 self.field = rel.field
607
608 @cached_property
609 def related_manager_cls(self):
610 related_model = self.rel.related_model
611
612 return create_reverse_many_to_one_manager(
613 related_model._default_manager.__class__,
614 self.rel,
615 )
616
617 def __get__(self, instance, cls=None):
618 """
619 Get the related objects through the reverse relation.
620
621 With the example above, when getting ``parent.children``:
622
623 - ``self`` is the descriptor managing the ``children`` attribute
624 - ``instance`` is the ``parent`` instance
625 - ``cls`` is the ``Parent`` class (unused)
626 """
627 if instance is None:
628 return self
629
630 return self.related_manager_cls(instance)
631
632 def _get_set_deprecation_msg_params(self):
633 return (
634 "reverse side of a related set",
635 self.rel.accessor_name,
636 )
637
638 def __set__(self, instance, value):
639 raise TypeError(
640 "Direct assignment to the %s is prohibited. Use %s.set() instead."
641 % self._get_set_deprecation_msg_params(),
642 )
643
644
645def create_reverse_many_to_one_manager(superclass, rel):
646 """
647 Create a manager for the reverse side of a many-to-one relation.
648
649 This manager subclasses another manager, generally the default manager of
650 the related model, and adds behaviors specific to many-to-one relations.
651 """
652
653 class RelatedManager(superclass, AltersData):
654 def __init__(self, instance):
655 super().__init__()
656
657 self.instance = instance
658 self.model = rel.related_model
659 self.field = rel.field
660
661 self.core_filters = {self.field.name: instance}
662
663 def __call__(self, *, manager):
664 manager = getattr(self.model, manager)
665 manager_class = create_reverse_many_to_one_manager(manager.__class__, rel)
666 return manager_class(self.instance)
667
668 do_not_call_in_templates = True
669
670 def _check_fk_val(self):
671 for field in self.field.foreign_related_fields:
672 if getattr(self.instance, field.attname) is None:
673 raise ValueError(
674 f'"{self.instance!r}" needs to have a value for field '
675 f'"{field.attname}" before this relationship can be used.'
676 )
677
678 def _apply_rel_filters(self, queryset):
679 """
680 Filter the queryset for the instance this manager is bound to.
681 """
682 db = self._db or router.db_for_read(self.model, instance=self.instance)
683 empty_strings_as_null = connections[
684 db
685 ].features.interprets_empty_strings_as_nulls
686 queryset._add_hints(instance=self.instance)
687 if self._db:
688 queryset = queryset.using(self._db)
689 queryset._defer_next_filter = True
690 queryset = queryset.filter(**self.core_filters)
691 for field in self.field.foreign_related_fields:
692 val = getattr(self.instance, field.attname)
693 if val is None or (val == "" and empty_strings_as_null):
694 return queryset.none()
695 if self.field.many_to_one:
696 # Guard against field-like objects such as GenericRelation
697 # that abuse create_reverse_many_to_one_manager() with reverse
698 # one-to-many relationships instead and break known related
699 # objects assignment.
700 try:
701 target_field = self.field.target_field
702 except FieldError:
703 # The relationship has multiple target fields. Use a tuple
704 # for related object id.
705 rel_obj_id = tuple(
706 [
707 getattr(self.instance, target_field.attname)
708 for target_field in self.field.path_infos[-1].target_fields
709 ]
710 )
711 else:
712 rel_obj_id = getattr(self.instance, target_field.attname)
713 queryset._known_related_objects = {
714 self.field: {rel_obj_id: self.instance}
715 }
716 return queryset
717
718 def _remove_prefetched_objects(self):
719 try:
720 self.instance._prefetched_objects_cache.pop(
721 self.field.remote_field.cache_name
722 )
723 except (AttributeError, KeyError):
724 pass # nothing to clear from cache
725
726 def get_queryset(self):
727 # Even if this relation is not to pk, we require still pk value.
728 # The wish is that the instance has been already saved to DB,
729 # although having a pk value isn't a guarantee of that.
730 if not self.instance._is_pk_set():
731 raise ValueError(
732 f"{self.instance.__class__.__name__!r} instance needs to have a "
733 f"primary key value before this relationship can be used."
734 )
735 try:
736 return self.instance._prefetched_objects_cache[
737 self.field.remote_field.cache_name
738 ]
739 except (AttributeError, KeyError):
740 queryset = super().get_queryset()
741 return self._apply_rel_filters(queryset)
742
743 def get_prefetch_querysets(self, instances, querysets=None):
744 if querysets and len(querysets) != 1:
745 raise ValueError(
746 "querysets argument of get_prefetch_querysets() should have a "
747 "length of 1."
748 )
749 queryset = querysets[0] if querysets else super().get_queryset()
750 queryset._add_hints(instance=instances[0])
751 queryset = queryset.using(queryset._db or self._db)
752
753 rel_obj_attr = self.field.get_local_related_value
754 instance_attr = self.field.get_foreign_related_value
755 instances_dict = {instance_attr(inst): inst for inst in instances}
756 queryset = _filter_prefetch_queryset(queryset, self.field.name, instances)
757
758 # Since we just bypassed this class' get_queryset(), we must manage
759 # the reverse relation manually.
760 for rel_obj in queryset:
761 if not self.field.is_cached(rel_obj):
762 instance = instances_dict[rel_obj_attr(rel_obj)]
763 setattr(rel_obj, self.field.name, instance)
764 cache_name = self.field.remote_field.cache_name
765 return queryset, rel_obj_attr, instance_attr, False, cache_name, False
766
767 def add(self, *objs, bulk=True):
768 self._check_fk_val()
769 self._remove_prefetched_objects()
770 db = router.db_for_write(self.model, instance=self.instance)
771
772 def check_and_update_obj(obj):
773 if not isinstance(obj, self.model):
774 raise TypeError(
775 "'%s' instance expected, got %r"
776 % (
777 self.model._meta.object_name,
778 obj,
779 )
780 )
781 setattr(obj, self.field.name, self.instance)
782
783 if bulk:
784 pks = []
785 for obj in objs:
786 check_and_update_obj(obj)
787 if obj._state.adding or obj._state.db != db:
788 raise ValueError(
789 "%r instance isn't saved. Use bulk=False or save "
790 "the object first." % obj
791 )
792 pks.append(obj.pk)
793 self.model._base_manager.using(db).filter(pk__in=pks).update(
794 **{
795 self.field.name: self.instance,
796 }
797 )
798 else:
799 with transaction.atomic(using=db, savepoint=False):
800 for obj in objs:
801 check_and_update_obj(obj)
802 obj.save()
803
804 add.alters_data = True
805
806 async def aadd(self, *objs, bulk=True):
807 return await sync_to_async(self.add)(*objs, bulk=bulk)
808
809 aadd.alters_data = True
810
811 def create(self, **kwargs):
812 self._check_fk_val()
813 self._remove_prefetched_objects()
814 kwargs[self.field.name] = self.instance
815 db = router.db_for_write(self.model, instance=self.instance)
816 return super(RelatedManager, self.db_manager(db)).create(**kwargs)
817
818 create.alters_data = True
819
820 async def acreate(self, **kwargs):
821 return await sync_to_async(self.create)(**kwargs)
822
823 acreate.alters_data = True
824
825 def get_or_create(self, **kwargs):
826 self._check_fk_val()
827 kwargs[self.field.name] = self.instance
828 db = router.db_for_write(self.model, instance=self.instance)
829 return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs)
830
831 get_or_create.alters_data = True
832
833 async def aget_or_create(self, **kwargs):
834 return await sync_to_async(self.get_or_create)(**kwargs)
835
836 aget_or_create.alters_data = True
837
838 def update_or_create(self, **kwargs):
839 self._check_fk_val()
840 kwargs[self.field.name] = self.instance
841 db = router.db_for_write(self.model, instance=self.instance)
842 return super(RelatedManager, self.db_manager(db)).update_or_create(**kwargs)
843
844 update_or_create.alters_data = True
845
846 async def aupdate_or_create(self, **kwargs):
847 return await sync_to_async(self.update_or_create)(**kwargs)
848
849 aupdate_or_create.alters_data = True
850
851 # remove() and clear() are only provided if the ForeignKey can have a
852 # value of null.
853 if rel.field.null:
854
855 def remove(self, *objs, bulk=True):
856 if not objs:
857 return
858 self._check_fk_val()
859 val = self.field.get_foreign_related_value(self.instance)
860 old_ids = set()
861 for obj in objs:
862 if not isinstance(obj, self.model):
863 raise TypeError(
864 "'%s' instance expected, got %r"
865 % (
866 self.model._meta.object_name,
867 obj,
868 )
869 )
870 # Is obj actually part of this descriptor set?
871 if self.field.get_local_related_value(obj) == val:
872 old_ids.add(obj.pk)
873 else:
874 raise self.field.remote_field.model.DoesNotExist(
875 "%r is not related to %r." % (obj, self.instance)
876 )
877 self._clear(self.filter(pk__in=old_ids), bulk)
878
879 remove.alters_data = True
880
881 async def aremove(self, *objs, bulk=True):
882 return await sync_to_async(self.remove)(*objs, bulk=bulk)
883
884 aremove.alters_data = True
885
886 def clear(self, *, bulk=True):
887 self._check_fk_val()
888 self._clear(self, bulk)
889
890 clear.alters_data = True
891
892 async def aclear(self, *, bulk=True):
893 return await sync_to_async(self.clear)(bulk=bulk)
894
895 aclear.alters_data = True
896
897 def _clear(self, queryset, bulk):
898 self._remove_prefetched_objects()
899 db = router.db_for_write(self.model, instance=self.instance)
900 queryset = queryset.using(db)
901 if bulk:
902 # `QuerySet.update()` is intrinsically atomic.
903 queryset.update(**{self.field.name: None})
904 else:
905 with transaction.atomic(using=db, savepoint=False):
906 for obj in queryset:
907 setattr(obj, self.field.name, None)
908 obj.save(update_fields=[self.field.name])
909
910 _clear.alters_data = True
911
912 def set(self, objs, *, bulk=True, clear=False):
913 self._check_fk_val()
914 # Force evaluation of `objs` in case it's a queryset whose value
915 # could be affected by `manager.clear()`. Refs #19816.
916 objs = tuple(objs)
917
918 if self.field.null:
919 db = router.db_for_write(self.model, instance=self.instance)
920 with transaction.atomic(using=db, savepoint=False):
921 if clear:
922 self.clear(bulk=bulk)
923 self.add(*objs, bulk=bulk)
924 else:
925 old_objs = set(self.using(db).all())
926 new_objs = []
927 for obj in objs:
928 if obj in old_objs:
929 old_objs.remove(obj)
930 else:
931 new_objs.append(obj)
932
933 self.remove(*old_objs, bulk=bulk)
934 self.add(*new_objs, bulk=bulk)
935 else:
936 self.add(*objs, bulk=bulk)
937
938 set.alters_data = True
939
940 async def aset(self, objs, *, bulk=True, clear=False):
941 return await sync_to_async(self.set)(objs=objs, bulk=bulk, clear=clear)
942
943 aset.alters_data = True
944
945 return RelatedManager
946
947
948class ManyToManyDescriptor(ReverseManyToOneDescriptor):
949 """
950 Accessor to the related objects manager on the forward and reverse sides of
951 a many-to-many relation.
952
953 In the example::
954
955 class Pizza(Model):
956 toppings = ManyToManyField(Topping, related_name='pizzas')
957
958 ``Pizza.toppings`` and ``Topping.pizzas`` are ``ManyToManyDescriptor``
959 instances.
960
961 Most of the implementation is delegated to a dynamically defined manager
962 class built by ``create_forward_many_to_many_manager()`` defined below.
963 """
964
965 def __init__(self, rel, reverse=False):
966 super().__init__(rel)
967
968 self.reverse = reverse
969
970 @property
971 def through(self):
972 # through is provided so that you have easy access to the through
973 # model (Book.authors.through) for inlines, etc. This is done as
974 # a property to ensure that the fully resolved value is returned.
975 return self.rel.through
976
977 @cached_property
978 def related_manager_cls(self):
979 related_model = self.rel.related_model if self.reverse else self.rel.model
980
981 return create_forward_many_to_many_manager(
982 related_model._default_manager.__class__,
983 self.rel,
984 reverse=self.reverse,
985 )
986
987 def _get_set_deprecation_msg_params(self):
988 return (
989 "%s side of a many-to-many set"
990 % ("reverse" if self.reverse else "forward"),
991 self.rel.accessor_name if self.reverse else self.field.name,
992 )
993
994
995def create_forward_many_to_many_manager(superclass, rel, reverse):
996 """
997 Create a manager for the either side of a many-to-many relation.
998
999 This manager subclasses another manager, generally the default manager of
1000 the related model, and adds behaviors specific to many-to-many relations.
1001 """
1002
1003 class ManyRelatedManager(superclass, AltersData):
1004 def __init__(self, instance=None):
1005 super().__init__()
1006
1007 self.instance = instance
1008
1009 if not reverse:
1010 self.model = rel.model
1011 self.query_field_name = rel.field.related_query_name()
1012 self.prefetch_cache_name = rel.field.name
1013 self.source_field_name = rel.field.m2m_field_name()
1014 self.target_field_name = rel.field.m2m_reverse_field_name()
1015 self.symmetrical = rel.symmetrical
1016 else:
1017 self.model = rel.related_model
1018 self.query_field_name = rel.field.name
1019 self.prefetch_cache_name = rel.field.related_query_name()
1020 self.source_field_name = rel.field.m2m_reverse_field_name()
1021 self.target_field_name = rel.field.m2m_field_name()
1022 self.symmetrical = False
1023
1024 self.through = rel.through
1025 self.reverse = reverse
1026
1027 self.source_field = self.through._meta.get_field(self.source_field_name)
1028 self.target_field = self.through._meta.get_field(self.target_field_name)
1029
1030 self.core_filters = {}
1031 self.pk_field_names = {}
1032 for lh_field, rh_field in self.source_field.related_fields:
1033 core_filter_key = "%s__%s" % (self.query_field_name, rh_field.name)
1034 self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
1035 self.pk_field_names[lh_field.name] = rh_field.name
1036
1037 self.related_val = self.source_field.get_foreign_related_value(instance)
1038 if None in self.related_val:
1039 raise ValueError(
1040 '"%r" needs to have a value for field "%s" before '
1041 "this many-to-many relationship can be used."
1042 % (instance, self.pk_field_names[self.source_field_name])
1043 )
1044 # Even if this relation is not to pk, we require still pk value.
1045 # The wish is that the instance has been already saved to DB,
1046 # although having a pk value isn't a guarantee of that.
1047 if not instance._is_pk_set():
1048 raise ValueError(
1049 "%r instance needs to have a primary key value before "
1050 "a many-to-many relationship can be used."
1051 % instance.__class__.__name__
1052 )
1053
1054 def __call__(self, *, manager):
1055 manager = getattr(self.model, manager)
1056 manager_class = create_forward_many_to_many_manager(
1057 manager.__class__, rel, reverse
1058 )
1059 return manager_class(instance=self.instance)
1060
1061 do_not_call_in_templates = True
1062
1063 def _build_remove_filters(self, removed_vals):
1064 filters = Q.create([(self.source_field_name, self.related_val)])
1065 # No need to add a subquery condition if removed_vals is a QuerySet without
1066 # filters.
1067 removed_vals_filters = (
1068 not isinstance(removed_vals, QuerySet) or removed_vals._has_filters()
1069 )
1070 if removed_vals_filters:
1071 filters &= Q.create([(f"{self.target_field_name}__in", removed_vals)])
1072 if self.symmetrical:
1073 symmetrical_filters = Q.create(
1074 [(self.target_field_name, self.related_val)]
1075 )
1076 if removed_vals_filters:
1077 symmetrical_filters &= Q.create(
1078 [(f"{self.source_field_name}__in", removed_vals)]
1079 )
1080 filters |= symmetrical_filters
1081 return filters
1082
1083 def _apply_rel_filters(self, queryset):
1084 """
1085 Filter the queryset for the instance this manager is bound to.
1086 """
1087 queryset._add_hints(instance=self.instance)
1088 if self._db:
1089 queryset = queryset.using(self._db)
1090 queryset._defer_next_filter = True
1091 return queryset._next_is_sticky().filter(**self.core_filters)
1092
1093 def get_prefetch_cache(self):
1094 try:
1095 return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
1096 except (AttributeError, KeyError):
1097 return None
1098
1099 def _remove_prefetched_objects(self):
1100 try:
1101 self.instance._prefetched_objects_cache.pop(self.prefetch_cache_name)
1102 except (AttributeError, KeyError):
1103 pass # nothing to clear from cache
1104
1105 def get_queryset(self):
1106 if (cache := self.get_prefetch_cache()) is not None:
1107 return cache
1108 else:
1109 queryset = super().get_queryset()
1110 return self._apply_rel_filters(queryset)
1111
1112 def get_prefetch_querysets(self, instances, querysets=None):
1113 if querysets and len(querysets) != 1:
1114 raise ValueError(
1115 "querysets argument of get_prefetch_querysets() should have a "
1116 "length of 1."
1117 )
1118 queryset = querysets[0] if querysets else super().get_queryset()
1119 queryset._add_hints(instance=instances[0])
1120 queryset = queryset.using(queryset._db or self._db)
1121 queryset = _filter_prefetch_queryset(
1122 queryset._next_is_sticky(), self.query_field_name, instances
1123 )
1124
1125 # M2M: need to annotate the query in order to get the primary model
1126 # that the secondary model was actually related to. We know that
1127 # there will already be a join on the join table, so we can just add
1128 # the select.
1129
1130 # For non-autocreated 'through' models, can't assume we are
1131 # dealing with PK values.
1132 fk = self.through._meta.get_field(self.source_field_name)
1133 join_table = fk.model._meta.db_table
1134 connection = connections[queryset.db]
1135 qn = connection.ops.quote_name
1136 queryset = queryset.extra(
1137 select={
1138 "_prefetch_related_val_%s"
1139 % f.attname: "%s.%s"
1140 % (qn(join_table), qn(f.column))
1141 for f in fk.local_related_fields
1142 }
1143 )
1144 return (
1145 queryset,
1146 lambda result: tuple(
1147 f.get_db_prep_value(
1148 getattr(result, f"_prefetch_related_val_{f.attname}"),
1149 connection,
1150 )
1151 for f in fk.local_related_fields
1152 ),
1153 lambda inst: tuple(
1154 f.get_db_prep_value(getattr(inst, f.attname), connection)
1155 for f in fk.foreign_related_fields
1156 ),
1157 False,
1158 self.prefetch_cache_name,
1159 False,
1160 )
1161
1162 @property
1163 def constrained_target(self):
1164 # If the through relation's target field's foreign integrity is
1165 # enforced, the query can be performed solely against the through
1166 # table as the INNER JOIN'ing against target table is unnecessary.
1167 if not self.target_field.db_constraint:
1168 return None
1169 db = router.db_for_read(self.through, instance=self.instance)
1170 if not connections[db].features.supports_foreign_keys:
1171 return None
1172 hints = {"instance": self.instance}
1173 manager = self.through._base_manager.db_manager(db, hints=hints)
1174 filters = {self.source_field_name: self.instance.pk}
1175 # Nullable target rows must be excluded as well as they would have
1176 # been filtered out from an INNER JOIN.
1177 if self.target_field.null:
1178 filters["%s__isnull" % self.target_field_name] = False
1179 return manager.filter(**filters)
1180
1181 def exists(self):
1182 if (
1183 superclass is Manager
1184 and self.get_prefetch_cache() is None
1185 and (constrained_target := self.constrained_target) is not None
1186 ):
1187 return constrained_target.exists()
1188 else:
1189 return super().exists()
1190
1191 def count(self):
1192 if (
1193 superclass is Manager
1194 and self.get_prefetch_cache() is None
1195 and (constrained_target := self.constrained_target) is not None
1196 ):
1197 return constrained_target.count()
1198 else:
1199 return super().count()
1200
1201 def add(self, *objs, through_defaults=None):
1202 self._remove_prefetched_objects()
1203 db = router.db_for_write(self.through, instance=self.instance)
1204 with transaction.atomic(using=db, savepoint=False):
1205 self._add_items(
1206 self.source_field_name,
1207 self.target_field_name,
1208 *objs,
1209 through_defaults=through_defaults,
1210 )
1211 # If this is a symmetrical m2m relation to self, add the mirror
1212 # entry in the m2m table.
1213 if self.symmetrical:
1214 self._add_items(
1215 self.target_field_name,
1216 self.source_field_name,
1217 *objs,
1218 through_defaults=through_defaults,
1219 )
1220
1221 add.alters_data = True
1222
1223 async def aadd(self, *objs, through_defaults=None):
1224 return await sync_to_async(self.add)(
1225 *objs, through_defaults=through_defaults
1226 )
1227
1228 aadd.alters_data = True
1229
1230 def remove(self, *objs):
1231 self._remove_prefetched_objects()
1232 self._remove_items(self.source_field_name, self.target_field_name, *objs)
1233
1234 remove.alters_data = True
1235
1236 async def aremove(self, *objs):
1237 return await sync_to_async(self.remove)(*objs)
1238
1239 aremove.alters_data = True
1240
1241 def clear(self):
1242 db = router.db_for_write(self.through, instance=self.instance)
1243 with transaction.atomic(using=db, savepoint=False):
1244 signals.m2m_changed.send(
1245 sender=self.through,
1246 action="pre_clear",
1247 instance=self.instance,
1248 reverse=self.reverse,
1249 model=self.model,
1250 pk_set=None,
1251 using=db,
1252 )
1253 self._remove_prefetched_objects()
1254 filters = self._build_remove_filters(super().get_queryset().using(db))
1255 self.through._default_manager.using(db).filter(filters).delete()
1256
1257 signals.m2m_changed.send(
1258 sender=self.through,
1259 action="post_clear",
1260 instance=self.instance,
1261 reverse=self.reverse,
1262 model=self.model,
1263 pk_set=None,
1264 using=db,
1265 )
1266
1267 clear.alters_data = True
1268
1269 async def aclear(self):
1270 return await sync_to_async(self.clear)()
1271
1272 aclear.alters_data = True
1273
1274 def set(self, objs, *, clear=False, through_defaults=None):
1275 # Force evaluation of `objs` in case it's a queryset whose value
1276 # could be affected by `manager.clear()`. Refs #19816.
1277 objs = tuple(objs)
1278
1279 db = router.db_for_write(self.through, instance=self.instance)
1280 with transaction.atomic(using=db, savepoint=False):
1281 if clear:
1282 self.clear()
1283 self.add(*objs, through_defaults=through_defaults)
1284 else:
1285 old_ids = set(
1286 self.using(db).values_list(
1287 self.target_field.target_field.attname, flat=True
1288 )
1289 )
1290
1291 new_objs = []
1292 for obj in objs:
1293 fk_val = (
1294 self.target_field.get_foreign_related_value(obj)[0]
1295 if isinstance(obj, self.model)
1296 else self.target_field.get_prep_value(obj)
1297 )
1298 if fk_val in old_ids:
1299 old_ids.remove(fk_val)
1300 else:
1301 new_objs.append(obj)
1302
1303 self.remove(*old_ids)
1304 self.add(*new_objs, through_defaults=through_defaults)
1305
1306 set.alters_data = True
1307
1308 async def aset(self, objs, *, clear=False, through_defaults=None):
1309 return await sync_to_async(self.set)(
1310 objs=objs, clear=clear, through_defaults=through_defaults
1311 )
1312
1313 aset.alters_data = True
1314
1315 def create(self, *, through_defaults=None, **kwargs):
1316 db = router.db_for_write(self.instance.__class__, instance=self.instance)
1317 new_obj = super(ManyRelatedManager, self.db_manager(db)).create(**kwargs)
1318 self.add(new_obj, through_defaults=through_defaults)
1319 return new_obj
1320
1321 create.alters_data = True
1322
1323 async def acreate(self, *, through_defaults=None, **kwargs):
1324 return await sync_to_async(self.create)(
1325 through_defaults=through_defaults, **kwargs
1326 )
1327
1328 acreate.alters_data = True
1329
1330 def get_or_create(self, *, through_defaults=None, **kwargs):
1331 db = router.db_for_write(self.instance.__class__, instance=self.instance)
1332 obj, created = super(ManyRelatedManager, self.db_manager(db)).get_or_create(
1333 **kwargs
1334 )
1335 # We only need to add() if created because if we got an object back
1336 # from get() then the relationship already exists.
1337 if created:
1338 self.add(obj, through_defaults=through_defaults)
1339 return obj, created
1340
1341 get_or_create.alters_data = True
1342
1343 async def aget_or_create(self, *, through_defaults=None, **kwargs):
1344 return await sync_to_async(self.get_or_create)(
1345 through_defaults=through_defaults, **kwargs
1346 )
1347
1348 aget_or_create.alters_data = True
1349
1350 def update_or_create(self, *, through_defaults=None, **kwargs):
1351 db = router.db_for_write(self.instance.__class__, instance=self.instance)
1352 obj, created = super(
1353 ManyRelatedManager, self.db_manager(db)
1354 ).update_or_create(**kwargs)
1355 # We only need to add() if created because if we got an object back
1356 # from get() then the relationship already exists.
1357 if created:
1358 self.add(obj, through_defaults=through_defaults)
1359 return obj, created
1360
1361 update_or_create.alters_data = True
1362
1363 async def aupdate_or_create(self, *, through_defaults=None, **kwargs):
1364 return await sync_to_async(self.update_or_create)(
1365 through_defaults=through_defaults, **kwargs
1366 )
1367
1368 aupdate_or_create.alters_data = True
1369
1370 def _get_target_ids(self, target_field_name, objs):
1371 """
1372 Return the set of ids of `objs` that the target field references.
1373 """
1374 from django.db.models import Model
1375
1376 target_ids = set()
1377 target_field = self.through._meta.get_field(target_field_name)
1378 for obj in objs:
1379 if isinstance(obj, self.model):
1380 if not router.allow_relation(obj, self.instance):
1381 raise ValueError(
1382 'Cannot add "%r": instance is on database "%s", '
1383 'value is on database "%s"'
1384 % (obj, self.instance._state.db, obj._state.db)
1385 )
1386 target_id = target_field.get_foreign_related_value(obj)[0]
1387 if target_id is None:
1388 raise ValueError(
1389 'Cannot add "%r": the value for field "%s" is None'
1390 % (obj, target_field_name)
1391 )
1392 target_ids.add(target_id)
1393 elif isinstance(obj, Model):
1394 raise TypeError(
1395 "'%s' instance expected, got %r"
1396 % (self.model._meta.object_name, obj)
1397 )
1398 else:
1399 target_ids.add(target_field.get_prep_value(obj))
1400 return target_ids
1401
1402 def _get_missing_target_ids(
1403 self, source_field_name, target_field_name, db, target_ids
1404 ):
1405 """
1406 Return the subset of ids of `objs` that aren't already assigned to
1407 this relationship.
1408 """
1409 vals = (
1410 self.through._default_manager.using(db)
1411 .values_list(target_field_name, flat=True)
1412 .filter(
1413 **{
1414 source_field_name: self.related_val[0],
1415 "%s__in" % target_field_name: target_ids,
1416 }
1417 )
1418 )
1419 return target_ids.difference(vals)
1420
1421 def _get_add_plan(self, db, source_field_name):
1422 """
1423 Return a boolean triple of the way the add should be performed.
1424
1425 The first element is whether or not bulk_create(ignore_conflicts)
1426 can be used, the second whether or not signals must be sent, and
1427 the third element is whether or not the immediate bulk insertion
1428 with conflicts ignored can be performed.
1429 """
1430 # Conflicts can be ignored when the intermediary model is
1431 # auto-created as the only possible collision is on the
1432 # (source_id, target_id) tuple. The same assertion doesn't hold for
1433 # user-defined intermediary models as they could have other fields
1434 # causing conflicts which must be surfaced.
1435 can_ignore_conflicts = (
1436 self.through._meta.auto_created is not False
1437 and connections[db].features.supports_ignore_conflicts
1438 )
1439 # Don't send the signal when inserting duplicate data row
1440 # for symmetrical reverse entries.
1441 must_send_signals = (
1442 self.reverse or source_field_name == self.source_field_name
1443 ) and (signals.m2m_changed.has_listeners(self.through))
1444 # Fast addition through bulk insertion can only be performed
1445 # if no m2m_changed listeners are connected for self.through
1446 # as they require the added set of ids to be provided via
1447 # pk_set.
1448 return (
1449 can_ignore_conflicts,
1450 must_send_signals,
1451 (can_ignore_conflicts and not must_send_signals),
1452 )
1453
1454 def _add_items(
1455 self, source_field_name, target_field_name, *objs, through_defaults=None
1456 ):
1457 # source_field_name: the PK fieldname in join table for the source object
1458 # target_field_name: the PK fieldname in join table for the target object
1459 # *objs - objects to add. Either object instances, or primary keys
1460 # of object instances.
1461 if not objs:
1462 return
1463
1464 through_defaults = dict(resolve_callables(through_defaults or {}))
1465 target_ids = self._get_target_ids(target_field_name, objs)
1466 db = router.db_for_write(self.through, instance=self.instance)
1467 can_ignore_conflicts, must_send_signals, can_fast_add = self._get_add_plan(
1468 db, source_field_name
1469 )
1470 if can_fast_add:
1471 self.through._default_manager.using(db).bulk_create(
1472 [
1473 self.through(
1474 **{
1475 "%s_id" % source_field_name: self.related_val[0],
1476 "%s_id" % target_field_name: target_id,
1477 }
1478 )
1479 for target_id in target_ids
1480 ],
1481 ignore_conflicts=True,
1482 )
1483 return
1484
1485 missing_target_ids = self._get_missing_target_ids(
1486 source_field_name, target_field_name, db, target_ids
1487 )
1488 with transaction.atomic(using=db, savepoint=False):
1489 if must_send_signals:
1490 signals.m2m_changed.send(
1491 sender=self.through,
1492 action="pre_add",
1493 instance=self.instance,
1494 reverse=self.reverse,
1495 model=self.model,
1496 pk_set=missing_target_ids,
1497 using=db,
1498 )
1499 # Add the ones that aren't there already.
1500 self.through._default_manager.using(db).bulk_create(
1501 [
1502 self.through(
1503 **through_defaults,
1504 **{
1505 "%s_id" % source_field_name: self.related_val[0],
1506 "%s_id" % target_field_name: target_id,
1507 },
1508 )
1509 for target_id in missing_target_ids
1510 ],
1511 ignore_conflicts=can_ignore_conflicts,
1512 )
1513
1514 if must_send_signals:
1515 signals.m2m_changed.send(
1516 sender=self.through,
1517 action="post_add",
1518 instance=self.instance,
1519 reverse=self.reverse,
1520 model=self.model,
1521 pk_set=missing_target_ids,
1522 using=db,
1523 )
1524
1525 def _remove_items(self, source_field_name, target_field_name, *objs):
1526 # source_field_name: the PK colname in join table for the source object
1527 # target_field_name: the PK colname in join table for the target object
1528 # *objs - objects to remove. Either object instances, or primary
1529 # keys of object instances.
1530 if not objs:
1531 return
1532
1533 # Check that all the objects are of the right type
1534 old_ids = set()
1535 for obj in objs:
1536 if isinstance(obj, self.model):
1537 fk_val = self.target_field.get_foreign_related_value(obj)[0]
1538 old_ids.add(fk_val)
1539 else:
1540 old_ids.add(obj)
1541
1542 db = router.db_for_write(self.through, instance=self.instance)
1543 with transaction.atomic(using=db, savepoint=False):
1544 # Send a signal to the other end if need be.
1545 signals.m2m_changed.send(
1546 sender=self.through,
1547 action="pre_remove",
1548 instance=self.instance,
1549 reverse=self.reverse,
1550 model=self.model,
1551 pk_set=old_ids,
1552 using=db,
1553 )
1554 target_model_qs = super().get_queryset()
1555 if target_model_qs._has_filters():
1556 old_vals = target_model_qs.using(db).filter(
1557 **{"%s__in" % self.target_field.target_field.attname: old_ids}
1558 )
1559 else:
1560 old_vals = old_ids
1561 filters = self._build_remove_filters(old_vals)
1562 self.through._default_manager.using(db).filter(filters).delete()
1563
1564 signals.m2m_changed.send(
1565 sender=self.through,
1566 action="post_remove",
1567 instance=self.instance,
1568 reverse=self.reverse,
1569 model=self.model,
1570 pk_set=old_ids,
1571 using=db,
1572 )
1573
1574 return ManyRelatedManager