Opened 8 months ago
Last modified 5 months ago
#36235 assigned Bug
RelatedManager.all().get_or_create() does not work
| Reported by: | Nick Pope | Owned by: | JaeHyuckSa |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | get_or_create, related, manager |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | yes |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
When accessing the queryset for a related manager, .get_or_create() and .update_or_create() lose context of the related instance.
Calling on the related manager works as expected:
publisher.books.get_or_create(name="The Very Hungry Caterpillar")
This is the case that was fixed by #3121 and #23611.
But calling on the queryset causes an IntegrityError to be raised:
publisher.books.all().get_or_create(name="The Very Hungry Caterpillar")
This can be a subtle failure that is hard to understand, especially if publisher.books.all() is assigned to a variable earlier.
The challenge here is that the overridden methods on the manager set kwargs[self.field.name] = self.instance.
We'd need to be able to pass this information down to the queryset. It looks like this might already be available in _known_related_objects which is set by RelatedManager._apply_rel_filters(), so that would be a good starting point for investigation.
We would also need to check whether something needs to be done to select the correct database as RelatedManager.get_or_create() has handling for this:
db = router.db_for_write(self.model, instance=self.instance)
If this is something we can't fix reliably, then we should update the admonition under .get_or_create() in the docs and probably update .update_or_create() to make this and other issues related to use through RelatedManager more clear.
Change History (7)
comment:1 by , 8 months ago
comment:2 by , 8 months ago
| Description: | modified (diff) |
|---|
comment:4 by , 8 months ago
| Has patch: | set |
|---|---|
| Owner: | set to |
| Status: | new → assigned |
comment:5 by , 8 months ago
| Has patch: | unset |
|---|
comment:6 by , 8 months ago
| Has patch: | set |
|---|
comment:7 by , 5 months ago
| Patch needs improvement: | set |
|---|
The following test can be added to
GetOrCreateTestsintests/get_or_create/tests.pybelowtest_get_or_create_on_related_manager: