-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Fixed #36235 -- Fixed RelatedManager queryset losing related instance in get_or_create()
and update_or_create()
.
#19241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Thanks for picking this up.
I think, looking at Also, are there any issues with doing this as regards the database router stuff in the |
… in get_or_create() and update_or_create(). Signed-off-by: saJaeHyukc <wogur981208@gmail.com>
@ngnpope Thank you for taking the time to review this despite your busy schedule.
I've added test code to examine this part, and it still returns a QuerySet. While I was able to check using
I agree with you on this point. I'm planning to add test code for the
I'll need a bit more time to look into this part, so I'll follow up with you later. |
I would add something like: --- a/tests/many_to_one/tests.py
+++ b/tests/many_to_one/tests.py
@@ -807,6 +807,11 @@ class ManyToOneTests(TestCase):
d2 = city.districts.create(name="Goa")
self.assertSequenceEqual(city.districts.all(), [d1, d2])
+ def test_create_on_related_queryset(self):
+ c = City.objects.create(name="Musical City")
+ c.districts.all().create(name="Ladida")
+ self.assertEqual(c.districts.count(), 1)
+
def test_clear_after_prefetch(self):
c = City.objects.create(name="Musical City") |
field, related_objects = next(iter(self._known_related_objects.items())) | ||
rel_obj = next(iter(related_objects.values())) | ||
kwargs[field.name] = rel_obj |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we are picking the first field and the first instance for this field? It will work in the test case but _known_related_objects
has a type of {field: {pk: Model}}
which can contain multiple fields and multiple instances when Queryset combination is used (see usage of _merge_known_related_objects
)
django/django/db/models/query.py
Lines 2008 to 2013 in bc1bfe1
def _merge_known_related_objects(self, other): | |
""" | |
Keep track of all known related objects from either QuerySet instance. | |
""" | |
for field, objects in other._known_related_objects.items(): | |
self._known_related_objects.setdefault(field, {}).update(objects) |
In other words, I don't think we can assume that _known_related_objects
will only contain a single field and related object as assigned by create_reverse_many_to_one_manager
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So from the queryset we lose reference to self.field
and self.instance
on the RelatedManager
. These are used by that manager to automatically pass in the related instance to .create()
, .get_or_create()
, and .update_or_create()
.
I'd merely seen that we already have access to these on the queryset via _known_related_objects
and thought that could be a useful starting point for investigation. Also I'd seen:
django/django/db/models/fields/related_descriptors.py
Lines 730 to 732 in 8b241f8
queryset._known_related_objects = { | |
self.field: {rel_obj_id: self.instance} | |
} |
I guess that we'll just have to duplicate this stuff and explicitly set another attribute on QuerySet
that we can use? Do you have any other ideas? 🤔
Trac ticket number
ticket-36235
Branch description
Fixed an issue where calling
get_or_create()
orupdate_or_create()
on a queryset obtained from RelatedManager.all() lost the context of the related instance, causing an IntegrityError.@ngnpope Thank you for providing the test code for this ticket.
Checklist
main
branch.