Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/db/models/fields/related_descriptors.py: 8%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

642 statements  

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