Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fields.py 26KB

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