[Django] #36235: RelatedManager.all().get_or_create() does not work

16 views
Skip to first unread message

Django

unread,
Mar 7, 2025, 6:19:07 AMMar 7
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: dev | Severity: Normal
Keywords: get_or_create, | Triage Stage:
related, manager | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
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:

{{{#!python
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:

{{{#!python
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.

If this is something we can't fix reliably, then we should update the
admonition under
[https://docs.djangoproject.com/en/stable/ref/models/querysets/#get-or-
create .get_or_create()] in the docs and probably update
[https://docs.djangoproject.com/en/stable/ref/models/querysets/#update-or-
create .update_or_create()] to make this and other issues related to use
through `RelatedManager` more clear.
--
Ticket URL: <https://code.djangoproject.com/ticket/36235>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Mar 7, 2025, 6:20:48 AMMar 7
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage:
related, manager | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Nick Pope):

The following test can be added to `GetOrCreateTests` in
`tests/get_or_create/tests.py` below
`test_get_or_create_on_related_manager`:

{{{#!python
def test_get_or_create_on_related_queryset(self):
p = Publisher.objects.create(name="Acme Publishing")
# Create a book through the publisher.
book, created = p.books.all().get_or_create(name="The Book of Ed &
Fred")
self.assertTrue(created)
# The publisher should have one book.
self.assertEqual(p.books.count(), 1)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:1>

Django

unread,
Mar 7, 2025, 6:28:34 AMMar 7
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage:
related, manager | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Nick Pope:

Old description:

> 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:
>
> {{{#!python
> 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:
>
> {{{#!python
> 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.
>
> If this is something we can't fix reliably, then we should update the
> admonition under
> [https://docs.djangoproject.com/en/stable/ref/models/querysets/#get-or-
> create .get_or_create()] in the docs and probably update
> [https://docs.djangoproject.com/en/stable/ref/models/querysets/#update-
> or-create .update_or_create()] to make this and other issues related to
> use through `RelatedManager` more clear.

New description:

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:

{{{#!python
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:

{{{#!python
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:

{{{#!python
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
[https://docs.djangoproject.com/en/stable/ref/models/querysets/#get-or-
create .get_or_create()] in the docs and probably update
[https://docs.djangoproject.com/en/stable/ref/models/querysets/#update-or-
create .update_or_create()] to make this and other issues related to use
through `RelatedManager` more clear.

--
--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:2>

Django

unread,
Mar 7, 2025, 7:32:28 AMMar 7
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage: Accepted
related, manager |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* stage: Unreviewed => Accepted

Comment:

Thank you for the report and test!
--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:3>

Django

unread,
Mar 8, 2025, 5:48:03 AMMar 8
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner:
| JaeHyuckSa
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage: Accepted
related, manager |
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by JaeHyuckSa):

* has_patch: 0 => 1
* owner: (none) => JaeHyuckSa
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:4>

Django

unread,
Mar 8, 2025, 5:55:14 AMMar 8
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner:
| JaeHyuckSa
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage: Accepted
related, manager |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by JaeHyuckSa):

* has_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:5>

Django

unread,
Mar 8, 2025, 11:26:56 AMMar 8
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner:
| JaeHyuckSa
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage: Accepted
related, manager |
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by JaeHyuckSa):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:6>

Django

unread,
Jun 18, 2025, 11:09:09 AMJun 18
to django-...@googlegroups.com
#36235: RelatedManager.all().get_or_create() does not work
-------------------------------------+-------------------------------------
Reporter: Nick Pope | Owner:
| JaeHyuckSa
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: get_or_create, | Triage Stage: Accepted
related, manager |
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36235#comment:7>
Reply all
Reply to author
Forward
0 new messages