fields.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. import functools
  2. import itertools
  3. import warnings
  4. from collections import defaultdict
  5. from asgiref.sync import sync_to_async
  6. from django.contrib.contenttypes.models import ContentType
  7. from django.core import checks
  8. from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
  9. from django.db import DEFAULT_DB_ALIAS, models, router, transaction
  10. from django.db.models import DO_NOTHING, ForeignObject, ForeignObjectRel
  11. from django.db.models.base import ModelBase, make_foreign_order_accessors
  12. from django.db.models.fields import Field
  13. from django.db.models.fields.mixins import FieldCacheMixin
  14. from django.db.models.fields.related import (
  15. ReverseManyToOneDescriptor,
  16. lazy_related_operation,
  17. )
  18. from django.db.models.query_utils import PathInfo
  19. from django.db.models.sql import AND
  20. from django.db.models.sql.where import WhereNode
  21. from django.db.models.utils import AltersData
  22. from django.utils.deprecation import RemovedInDjango60Warning
  23. from django.utils.functional import cached_property
  24. class GenericForeignKey(FieldCacheMixin, Field):
  25. """
  26. Provide a generic many-to-one relation through the ``content_type`` and
  27. ``object_id`` fields.
  28. This class also doubles as an accessor to the related object (similar to
  29. ForwardManyToOneDescriptor) by adding itself as a model attribute.
  30. """
  31. many_to_many = False
  32. many_to_one = True
  33. one_to_many = False
  34. one_to_one = False
  35. def __init__(
  36. self, ct_field="content_type", fk_field="object_id", for_concrete_model=True
  37. ):
  38. super().__init__(editable=False)
  39. self.ct_field = ct_field
  40. self.fk_field = fk_field
  41. self.for_concrete_model = for_concrete_model
  42. self.is_relation = True
  43. def contribute_to_class(self, cls, name, **kwargs):
  44. super().contribute_to_class(cls, name, private_only=True, **kwargs)
  45. # GenericForeignKey is its own descriptor.
  46. setattr(cls, self.attname, self)
  47. def get_attname_column(self):
  48. attname, column = super().get_attname_column()
  49. return attname, None
  50. def get_filter_kwargs_for_object(self, obj):
  51. """See corresponding method on Field"""
  52. return {
  53. self.fk_field: getattr(obj, self.fk_field),
  54. self.ct_field: getattr(obj, self.ct_field),
  55. }
  56. def get_forward_related_filter(self, obj):
  57. """See corresponding method on RelatedField"""
  58. return {
  59. self.fk_field: obj.pk,
  60. self.ct_field: ContentType.objects.get_for_model(obj).pk,
  61. }
  62. def check(self, **kwargs):
  63. return [
  64. *self._check_field_name(),
  65. *self._check_object_id_field(),
  66. *self._check_content_type_field(),
  67. ]
  68. def _check_object_id_field(self):
  69. try:
  70. self.model._meta.get_field(self.fk_field)
  71. except FieldDoesNotExist:
  72. return [
  73. checks.Error(
  74. "The GenericForeignKey object ID references the "
  75. "nonexistent field '%s'." % self.fk_field,
  76. obj=self,
  77. id="contenttypes.E001",
  78. )
  79. ]
  80. else:
  81. return []
  82. def _check_content_type_field(self):
  83. """
  84. Check if field named `field_name` in model `model` exists and is a
  85. valid content_type field (is a ForeignKey to ContentType).
  86. """
  87. try:
  88. field = self.model._meta.get_field(self.ct_field)
  89. except FieldDoesNotExist:
  90. return [
  91. checks.Error(
  92. "The GenericForeignKey content type references the "
  93. "nonexistent field '%s.%s'."
  94. % (self.model._meta.object_name, self.ct_field),
  95. obj=self,
  96. id="contenttypes.E002",
  97. )
  98. ]
  99. else:
  100. if not isinstance(field, models.ForeignKey):
  101. return [
  102. checks.Error(
  103. "'%s.%s' is not a ForeignKey."
  104. % (self.model._meta.object_name, self.ct_field),
  105. hint=(
  106. "GenericForeignKeys must use a ForeignKey to "
  107. "'contenttypes.ContentType' as the 'content_type' field."
  108. ),
  109. obj=self,
  110. id="contenttypes.E003",
  111. )
  112. ]
  113. elif field.remote_field.model != ContentType:
  114. return [
  115. checks.Error(
  116. "'%s.%s' is not a ForeignKey to 'contenttypes.ContentType'."
  117. % (self.model._meta.object_name, self.ct_field),
  118. hint=(
  119. "GenericForeignKeys must use a ForeignKey to "
  120. "'contenttypes.ContentType' as the 'content_type' field."
  121. ),
  122. obj=self,
  123. id="contenttypes.E004",
  124. )
  125. ]
  126. else:
  127. return []
  128. @cached_property
  129. def cache_name(self):
  130. return self.name
  131. def get_content_type(self, obj=None, id=None, using=None, model=None):
  132. if obj is not None:
  133. return ContentType.objects.db_manager(obj._state.db).get_for_model(
  134. obj, for_concrete_model=self.for_concrete_model
  135. )
  136. elif id is not None:
  137. return ContentType.objects.db_manager(using).get_for_id(id)
  138. elif model is not None:
  139. return ContentType.objects.db_manager(using).get_for_model(
  140. model, for_concrete_model=self.for_concrete_model
  141. )
  142. else:
  143. # This should never happen. I love comments like this, don't you?
  144. raise Exception("Impossible arguments to GFK.get_content_type!")
  145. def get_prefetch_queryset(self, instances, queryset=None):
  146. warnings.warn(
  147. "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
  148. "instead.",
  149. RemovedInDjango60Warning,
  150. stacklevel=2,
  151. )
  152. if queryset is None:
  153. return self.get_prefetch_querysets(instances)
  154. return self.get_prefetch_querysets(instances, [queryset])
  155. def get_prefetch_querysets(self, instances, querysets=None):
  156. custom_queryset_dict = {}
  157. if querysets is not None:
  158. for queryset in querysets:
  159. ct_id = self.get_content_type(
  160. model=queryset.query.model, using=queryset.db
  161. ).pk
  162. if ct_id in custom_queryset_dict:
  163. raise ValueError(
  164. "Only one queryset is allowed for each content type."
  165. )
  166. custom_queryset_dict[ct_id] = queryset
  167. # For efficiency, group the instances by content type and then do one
  168. # query per model
  169. fk_dict = defaultdict(set)
  170. # We need one instance for each group in order to get the right db:
  171. instance_dict = {}
  172. ct_attname = self.model._meta.get_field(self.ct_field).attname
  173. for instance in instances:
  174. # We avoid looking for values if either ct_id or fkey value is None
  175. ct_id = getattr(instance, ct_attname)
  176. if ct_id is not None:
  177. fk_val = getattr(instance, self.fk_field)
  178. if fk_val is not None:
  179. fk_dict[ct_id].add(fk_val)
  180. instance_dict[ct_id] = instance
  181. ret_val = []
  182. for ct_id, fkeys in fk_dict.items():
  183. if ct_id in custom_queryset_dict:
  184. # Return values from the custom queryset, if provided.
  185. ret_val.extend(custom_queryset_dict[ct_id].filter(pk__in=fkeys))
  186. else:
  187. instance = instance_dict[ct_id]
  188. ct = self.get_content_type(id=ct_id, using=instance._state.db)
  189. ret_val.extend(ct.get_all_objects_for_this_type(pk__in=fkeys))
  190. # For doing the join in Python, we have to match both the FK val and the
  191. # content type, so we use a callable that returns a (fk, class) pair.
  192. def gfk_key(obj):
  193. ct_id = getattr(obj, ct_attname)
  194. if ct_id is None:
  195. return None
  196. else:
  197. model = self.get_content_type(
  198. id=ct_id, using=obj._state.db
  199. ).model_class()
  200. return (
  201. model._meta.pk.get_prep_value(getattr(obj, self.fk_field)),
  202. model,
  203. )
  204. return (
  205. ret_val,
  206. lambda obj: (obj.pk, obj.__class__),
  207. gfk_key,
  208. True,
  209. self.name,
  210. False,
  211. )
  212. def __get__(self, instance, cls=None):
  213. if instance is None:
  214. return self
  215. # Don't use getattr(instance, self.ct_field) here because that might
  216. # reload the same ContentType over and over (#5570). Instead, get the
  217. # content type ID here, and later when the actual instance is needed,
  218. # use ContentType.objects.get_for_id(), which has a global cache.
  219. f = self.model._meta.get_field(self.ct_field)
  220. ct_id = getattr(instance, f.attname, None)
  221. pk_val = getattr(instance, self.fk_field)
  222. rel_obj = self.get_cached_value(instance, default=None)
  223. if rel_obj is None and self.is_cached(instance):
  224. return rel_obj
  225. if rel_obj is not None:
  226. ct_match = (
  227. ct_id == self.get_content_type(obj=rel_obj, using=instance._state.db).id
  228. )
  229. pk_match = ct_match and rel_obj._meta.pk.to_python(pk_val) == rel_obj.pk
  230. if pk_match:
  231. return rel_obj
  232. else:
  233. rel_obj = None
  234. if ct_id is not None:
  235. ct = self.get_content_type(id=ct_id, using=instance._state.db)
  236. try:
  237. rel_obj = ct.get_object_for_this_type(
  238. using=instance._state.db, pk=pk_val
  239. )
  240. except ObjectDoesNotExist:
  241. pass
  242. self.set_cached_value(instance, rel_obj)
  243. return rel_obj
  244. def __set__(self, instance, value):
  245. ct = None
  246. fk = None
  247. if value is not None:
  248. ct = self.get_content_type(obj=value)
  249. fk = value.pk
  250. setattr(instance, self.ct_field, ct)
  251. setattr(instance, self.fk_field, fk)
  252. self.set_cached_value(instance, value)
  253. class GenericRel(ForeignObjectRel):
  254. """
  255. Used by GenericRelation to store information about the relation.
  256. """
  257. def __init__(
  258. self,
  259. field,
  260. to,
  261. related_name=None,
  262. related_query_name=None,
  263. limit_choices_to=None,
  264. ):
  265. super().__init__(
  266. field,
  267. to,
  268. related_name=related_query_name or "+",
  269. related_query_name=related_query_name,
  270. limit_choices_to=limit_choices_to,
  271. on_delete=DO_NOTHING,
  272. )
  273. class GenericRelation(ForeignObject):
  274. """
  275. Provide a reverse to a relation created by a GenericForeignKey.
  276. """
  277. # Field flags
  278. auto_created = False
  279. empty_strings_allowed = False
  280. many_to_many = False
  281. many_to_one = False
  282. one_to_many = True
  283. one_to_one = False
  284. rel_class = GenericRel
  285. mti_inherited = False
  286. def __init__(
  287. self,
  288. to,
  289. object_id_field="object_id",
  290. content_type_field="content_type",
  291. for_concrete_model=True,
  292. related_query_name=None,
  293. limit_choices_to=None,
  294. **kwargs,
  295. ):
  296. kwargs["rel"] = self.rel_class(
  297. self,
  298. to,
  299. related_query_name=related_query_name,
  300. limit_choices_to=limit_choices_to,
  301. )
  302. # Reverse relations are always nullable (Django can't enforce that a
  303. # foreign key on the related model points to this model).
  304. kwargs["null"] = True
  305. kwargs["blank"] = True
  306. kwargs["on_delete"] = models.CASCADE
  307. kwargs["editable"] = False
  308. kwargs["serialize"] = False
  309. # This construct is somewhat of an abuse of ForeignObject. This field
  310. # represents a relation from pk to object_id field. But, this relation
  311. # isn't direct, the join is generated reverse along foreign key. So,
  312. # the from_field is object_id field, to_field is pk because of the
  313. # reverse join.
  314. super().__init__(to, from_fields=[object_id_field], to_fields=[], **kwargs)
  315. self.object_id_field_name = object_id_field
  316. self.content_type_field_name = content_type_field
  317. self.for_concrete_model = for_concrete_model
  318. def check(self, **kwargs):
  319. return [
  320. *super().check(**kwargs),
  321. *self._check_generic_foreign_key_existence(),
  322. ]
  323. def _is_matching_generic_foreign_key(self, field):
  324. """
  325. Return True if field is a GenericForeignKey whose content type and
  326. object id fields correspond to the equivalent attributes on this
  327. GenericRelation.
  328. """
  329. return (
  330. isinstance(field, GenericForeignKey)
  331. and field.ct_field == self.content_type_field_name
  332. and field.fk_field == self.object_id_field_name
  333. )
  334. def _check_generic_foreign_key_existence(self):
  335. target = self.remote_field.model
  336. if isinstance(target, ModelBase):
  337. fields = target._meta.private_fields
  338. if any(self._is_matching_generic_foreign_key(field) for field in fields):
  339. return []
  340. else:
  341. return [
  342. checks.Error(
  343. "The GenericRelation defines a relation with the model "
  344. "'%s', but that model does not have a GenericForeignKey."
  345. % target._meta.label,
  346. obj=self,
  347. id="contenttypes.E004",
  348. )
  349. ]
  350. else:
  351. return []
  352. def resolve_related_fields(self):
  353. self.to_fields = [self.model._meta.pk.name]
  354. return [
  355. (
  356. self.remote_field.model._meta.get_field(self.object_id_field_name),
  357. self.model._meta.pk,
  358. )
  359. ]
  360. def _get_path_info_with_parent(self, filtered_relation):
  361. """
  362. Return the path that joins the current model through any parent models.
  363. The idea is that if you have a GFK defined on a parent model then we
  364. need to join the parent model first, then the child model.
  365. """
  366. # With an inheritance chain ChildTag -> Tag and Tag defines the
  367. # GenericForeignKey, and a TaggedItem model has a GenericRelation to
  368. # ChildTag, then we need to generate a join from TaggedItem to Tag
  369. # (as Tag.object_id == TaggedItem.pk), and another join from Tag to
  370. # ChildTag (as that is where the relation is to). Do this by first
  371. # generating a join to the parent model, then generating joins to the
  372. # child models.
  373. path = []
  374. opts = self.remote_field.model._meta.concrete_model._meta
  375. parent_opts = opts.get_field(self.object_id_field_name).model._meta
  376. target = parent_opts.pk
  377. path.append(
  378. PathInfo(
  379. from_opts=self.model._meta,
  380. to_opts=parent_opts,
  381. target_fields=(target,),
  382. join_field=self.remote_field,
  383. m2m=True,
  384. direct=False,
  385. filtered_relation=filtered_relation,
  386. )
  387. )
  388. # Collect joins needed for the parent -> child chain. This is easiest
  389. # to do if we collect joins for the child -> parent chain and then
  390. # reverse the direction (call to reverse() and use of
  391. # field.remote_field.get_path_info()).
  392. parent_field_chain = []
  393. while parent_opts != opts:
  394. field = opts.get_ancestor_link(parent_opts.model)
  395. parent_field_chain.append(field)
  396. opts = field.remote_field.model._meta
  397. parent_field_chain.reverse()
  398. for field in parent_field_chain:
  399. path.extend(field.remote_field.path_infos)
  400. return path
  401. def get_path_info(self, filtered_relation=None):
  402. opts = self.remote_field.model._meta
  403. object_id_field = opts.get_field(self.object_id_field_name)
  404. if object_id_field.model != opts.model:
  405. return self._get_path_info_with_parent(filtered_relation)
  406. else:
  407. target = opts.pk
  408. return [
  409. PathInfo(
  410. from_opts=self.model._meta,
  411. to_opts=opts,
  412. target_fields=(target,),
  413. join_field=self.remote_field,
  414. m2m=True,
  415. direct=False,
  416. filtered_relation=filtered_relation,
  417. )
  418. ]
  419. def get_reverse_path_info(self, filtered_relation=None):
  420. opts = self.model._meta
  421. from_opts = self.remote_field.model._meta
  422. return [
  423. PathInfo(
  424. from_opts=from_opts,
  425. to_opts=opts,
  426. target_fields=(opts.pk,),
  427. join_field=self,
  428. m2m=False,
  429. direct=False,
  430. filtered_relation=filtered_relation,
  431. )
  432. ]
  433. def value_to_string(self, obj):
  434. qs = getattr(obj, self.name).all()
  435. return str([instance.pk for instance in qs])
  436. def contribute_to_class(self, cls, name, **kwargs):
  437. kwargs["private_only"] = True
  438. super().contribute_to_class(cls, name, **kwargs)
  439. self.model = cls
  440. # Disable the reverse relation for fields inherited by subclasses of a
  441. # model in multi-table inheritance. The reverse relation points to the
  442. # field of the base model.
  443. if self.mti_inherited:
  444. self.remote_field.related_name = "+"
  445. self.remote_field.related_query_name = None
  446. setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field))
  447. # Add get_RELATED_order() and set_RELATED_order() to the model this
  448. # field belongs to, if the model on the other end of this relation
  449. # is ordered with respect to its corresponding GenericForeignKey.
  450. if not cls._meta.abstract:
  451. def make_generic_foreign_order_accessors(related_model, model):
  452. if self._is_matching_generic_foreign_key(
  453. model._meta.order_with_respect_to
  454. ):
  455. make_foreign_order_accessors(model, related_model)
  456. lazy_related_operation(
  457. make_generic_foreign_order_accessors,
  458. self.model,
  459. self.remote_field.model,
  460. )
  461. def set_attributes_from_rel(self):
  462. pass
  463. def get_internal_type(self):
  464. return "ManyToManyField"
  465. def get_content_type(self):
  466. """
  467. Return the content type associated with this field's model.
  468. """
  469. return ContentType.objects.get_for_model(
  470. self.model, for_concrete_model=self.for_concrete_model
  471. )
  472. def get_extra_restriction(self, alias, remote_alias):
  473. field = self.remote_field.model._meta.get_field(self.content_type_field_name)
  474. contenttype_pk = self.get_content_type().pk
  475. lookup = field.get_lookup("exact")(field.get_col(remote_alias), contenttype_pk)
  476. return WhereNode([lookup], connector=AND)
  477. def bulk_related_objects(self, objs, using=DEFAULT_DB_ALIAS):
  478. """
  479. Return all objects related to ``objs`` via this ``GenericRelation``.
  480. """
  481. return self.remote_field.model._base_manager.db_manager(using).filter(
  482. **{
  483. "%s__pk"
  484. % self.content_type_field_name: ContentType.objects.db_manager(using)
  485. .get_for_model(self.model, for_concrete_model=self.for_concrete_model)
  486. .pk,
  487. "%s__in" % self.object_id_field_name: [obj.pk for obj in objs],
  488. }
  489. )
  490. class ReverseGenericManyToOneDescriptor(ReverseManyToOneDescriptor):
  491. """
  492. Accessor to the related objects manager on the one-to-many relation created
  493. by GenericRelation.
  494. In the example::
  495. class Post(Model):
  496. comments = GenericRelation(Comment)
  497. ``post.comments`` is a ReverseGenericManyToOneDescriptor instance.
  498. """
  499. @cached_property
  500. def related_manager_cls(self):
  501. return create_generic_related_manager(
  502. self.rel.model._default_manager.__class__,
  503. self.rel,
  504. )
  505. def create_generic_related_manager(superclass, rel):
  506. """
  507. Factory function to create a manager that subclasses another manager
  508. (generally the default manager of a given model) and adds behaviors
  509. specific to generic relations.
  510. """
  511. class GenericRelatedObjectManager(superclass, AltersData):
  512. def __init__(self, instance=None):
  513. super().__init__()
  514. self.instance = instance
  515. self.model = rel.model
  516. self.get_content_type = functools.partial(
  517. ContentType.objects.db_manager(instance._state.db).get_for_model,
  518. for_concrete_model=rel.field.for_concrete_model,
  519. )
  520. self.content_type = self.get_content_type(instance)
  521. self.content_type_field_name = rel.field.content_type_field_name
  522. self.object_id_field_name = rel.field.object_id_field_name
  523. self.prefetch_cache_name = rel.field.attname
  524. self.pk_val = instance.pk
  525. self.core_filters = {
  526. "%s__pk" % self.content_type_field_name: self.content_type.id,
  527. self.object_id_field_name: self.pk_val,
  528. }
  529. def __call__(self, *, manager):
  530. manager = getattr(self.model, manager)
  531. manager_class = create_generic_related_manager(manager.__class__, rel)
  532. return manager_class(instance=self.instance)
  533. do_not_call_in_templates = True
  534. def __str__(self):
  535. return repr(self)
  536. def _apply_rel_filters(self, queryset):
  537. """
  538. Filter the queryset for the instance this manager is bound to.
  539. """
  540. db = self._db or router.db_for_read(self.model, instance=self.instance)
  541. return queryset.using(db).filter(**self.core_filters)
  542. def _remove_prefetched_objects(self):
  543. try:
  544. self.instance._prefetched_objects_cache.pop(self.prefetch_cache_name)
  545. except (AttributeError, KeyError):
  546. pass # nothing to clear from cache
  547. def get_queryset(self):
  548. try:
  549. return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
  550. except (AttributeError, KeyError):
  551. queryset = super().get_queryset()
  552. return self._apply_rel_filters(queryset)
  553. def get_prefetch_queryset(self, instances, queryset=None):
  554. warnings.warn(
  555. "get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
  556. "instead.",
  557. RemovedInDjango60Warning,
  558. stacklevel=2,
  559. )
  560. if queryset is None:
  561. return self.get_prefetch_querysets(instances)
  562. return self.get_prefetch_querysets(instances, [queryset])
  563. def get_prefetch_querysets(self, instances, querysets=None):
  564. if querysets and len(querysets) != 1:
  565. raise ValueError(
  566. "querysets argument of get_prefetch_querysets() should have a "
  567. "length of 1."
  568. )
  569. queryset = querysets[0] if querysets else super().get_queryset()
  570. queryset._add_hints(instance=instances[0])
  571. queryset = queryset.using(queryset._db or self._db)
  572. # Group instances by content types.
  573. content_type_queries = [
  574. models.Q.create(
  575. [
  576. (f"{self.content_type_field_name}__pk", content_type_id),
  577. (f"{self.object_id_field_name}__in", {obj.pk for obj in objs}),
  578. ]
  579. )
  580. for content_type_id, objs in itertools.groupby(
  581. sorted(instances, key=lambda obj: self.get_content_type(obj).pk),
  582. lambda obj: self.get_content_type(obj).pk,
  583. )
  584. ]
  585. query = models.Q.create(content_type_queries, connector=models.Q.OR)
  586. # We (possibly) need to convert object IDs to the type of the
  587. # instances' PK in order to match up instances:
  588. object_id_converter = instances[0]._meta.pk.to_python
  589. content_type_id_field_name = "%s_id" % self.content_type_field_name
  590. return (
  591. queryset.filter(query),
  592. lambda relobj: (
  593. object_id_converter(getattr(relobj, self.object_id_field_name)),
  594. getattr(relobj, content_type_id_field_name),
  595. ),
  596. lambda obj: (obj.pk, self.get_content_type(obj).pk),
  597. False,
  598. self.prefetch_cache_name,
  599. False,
  600. )
  601. def add(self, *objs, bulk=True):
  602. self._remove_prefetched_objects()
  603. db = router.db_for_write(self.model, instance=self.instance)
  604. def check_and_update_obj(obj):
  605. if not isinstance(obj, self.model):
  606. raise TypeError(
  607. "'%s' instance expected, got %r"
  608. % (self.model._meta.object_name, obj)
  609. )
  610. setattr(obj, self.content_type_field_name, self.content_type)
  611. setattr(obj, self.object_id_field_name, self.pk_val)
  612. if bulk:
  613. pks = []
  614. for obj in objs:
  615. if obj._state.adding or obj._state.db != db:
  616. raise ValueError(
  617. "%r instance isn't saved. Use bulk=False or save "
  618. "the object first." % obj
  619. )
  620. check_and_update_obj(obj)
  621. pks.append(obj.pk)
  622. self.model._base_manager.using(db).filter(pk__in=pks).update(
  623. **{
  624. self.content_type_field_name: self.content_type,
  625. self.object_id_field_name: self.pk_val,
  626. }
  627. )
  628. else:
  629. with transaction.atomic(using=db, savepoint=False):
  630. for obj in objs:
  631. check_and_update_obj(obj)
  632. obj.save()
  633. add.alters_data = True
  634. async def aadd(self, *objs, bulk=True):
  635. return await sync_to_async(self.add)(*objs, bulk=bulk)
  636. aadd.alters_data = True
  637. def remove(self, *objs, bulk=True):
  638. if not objs:
  639. return
  640. self._clear(self.filter(pk__in=[o.pk for o in objs]), bulk)
  641. remove.alters_data = True
  642. async def aremove(self, *objs, bulk=True):
  643. return await sync_to_async(self.remove)(*objs, bulk=bulk)
  644. aremove.alters_data = True
  645. def clear(self, *, bulk=True):
  646. self._clear(self, bulk)
  647. clear.alters_data = True
  648. async def aclear(self, *, bulk=True):
  649. return await sync_to_async(self.clear)(bulk=bulk)
  650. aclear.alters_data = True
  651. def _clear(self, queryset, bulk):
  652. self._remove_prefetched_objects()
  653. db = router.db_for_write(self.model, instance=self.instance)
  654. queryset = queryset.using(db)
  655. if bulk:
  656. # `QuerySet.delete()` creates its own atomic block which
  657. # contains the `pre_delete` and `post_delete` signal handlers.
  658. queryset.delete()
  659. else:
  660. with transaction.atomic(using=db, savepoint=False):
  661. for obj in queryset:
  662. obj.delete()
  663. _clear.alters_data = True
  664. def set(self, objs, *, bulk=True, clear=False):
  665. # Force evaluation of `objs` in case it's a queryset whose value
  666. # could be affected by `manager.clear()`. Refs #19816.
  667. objs = tuple(objs)
  668. db = router.db_for_write(self.model, instance=self.instance)
  669. with transaction.atomic(using=db, savepoint=False):
  670. if clear:
  671. self.clear()
  672. self.add(*objs, bulk=bulk)
  673. else:
  674. old_objs = set(self.using(db).all())
  675. new_objs = []
  676. for obj in objs:
  677. if obj in old_objs:
  678. old_objs.remove(obj)
  679. else:
  680. new_objs.append(obj)
  681. self.remove(*old_objs)
  682. self.add(*new_objs, bulk=bulk)
  683. set.alters_data = True
  684. async def aset(self, objs, *, bulk=True, clear=False):
  685. return await sync_to_async(self.set)(objs, bulk=bulk, clear=clear)
  686. aset.alters_data = True
  687. def create(self, **kwargs):
  688. self._remove_prefetched_objects()
  689. kwargs[self.content_type_field_name] = self.content_type
  690. kwargs[self.object_id_field_name] = self.pk_val
  691. db = router.db_for_write(self.model, instance=self.instance)
  692. return super().using(db).create(**kwargs)
  693. create.alters_data = True
  694. async def acreate(self, **kwargs):
  695. return await sync_to_async(self.create)(**kwargs)
  696. acreate.alters_data = True
  697. def get_or_create(self, **kwargs):
  698. kwargs[self.content_type_field_name] = self.content_type
  699. kwargs[self.object_id_field_name] = self.pk_val
  700. db = router.db_for_write(self.model, instance=self.instance)
  701. return super().using(db).get_or_create(**kwargs)
  702. get_or_create.alters_data = True
  703. async def aget_or_create(self, **kwargs):
  704. return await sync_to_async(self.get_or_create)(**kwargs)
  705. aget_or_create.alters_data = True
  706. def update_or_create(self, **kwargs):
  707. kwargs[self.content_type_field_name] = self.content_type
  708. kwargs[self.object_id_field_name] = self.pk_val
  709. db = router.db_for_write(self.model, instance=self.instance)
  710. return super().using(db).update_or_create(**kwargs)
  711. update_or_create.alters_data = True
  712. async def aupdate_or_create(self, **kwargs):
  713. return await sync_to_async(self.update_or_create)(**kwargs)
  714. aupdate_or_create.alters_data = True
  715. return GenericRelatedObjectManager