Opened 5 years ago
Last modified 5 years ago
#30796 closed Bug
Chaining select_related mutates original QuerySet. — at Initial Version
Reported by: | Darren Maki | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 2.2 |
Severity: | Normal | Keywords: | select_related prefetch_related mutate queryset |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When creating a new QuerySet from an existing QuerySet that has had 'select_related' applied, if you apply another 'select_related' to the new QuerySet it will mutate the original QuerySet to also have the extra 'select_related'.
models.py
from django.db import models class ModelA(models.Model): pass class ModelB(models.Model): pass class ModelC(models.Model): model_a = models.ForeignKey('foobar.ModelA', on_delete=models.CASCADE) model_b = models.ForeignKey('foobar.ModelB', on_delete=models.CASCADE)
test.py
query_1 = ModelC.objects.select_related('model_a') print('QUERY 1:', str(query_1.query)) query_2 = query_1.select_related('model_b') print('QUERY 2:', str(query_2.query)) print('QUERY 1:', str(query_1.query)) if str(query_1.query) == str(query_2.query): print('\n!!! The two queries are the same !!!\n')
output
QUERY 1: SELECT "foobar_modelc"."id", "foobar_modelc"."model_a_id", "foobar_modelc"."model_b_id", "foobar_modela"."id" FROM "foobar_modelc" INNER JOIN "foobar_modela" ON ("foobar_modelc"."model_a_id" = "foobar_modela"."id") 139663365718536 QUERY 2: SELECT "foobar_modelc"."id", "foobar_modelc"."model_a_id", "foobar_modelc"."model_b_id", "foobar_modela"."id", "foobar_modelb"."id" FROM "foobar_modelc" INNER JOIN "foobar_modela" ON ("foobar_modelc"."model_a_id" = "foobar_modela"."id") INNER JOIN "foobar_modelb" ON ("foobar_modelc"."model_b_id" = "foobar_modelb"."id") 139663366175376 QUERY 1: SELECT "foobar_modelc"."id", "foobar_modelc"."model_a_id", "foobar_modelc"."model_b_id", "foobar_modela"."id", "foobar_modelb"."id" FROM "foobar_modelc" INNER JOIN "foobar_modela" ON ("foobar_modelc"."model_a_id" = "foobar_modela"."id") INNER JOIN "foobar_modelb" ON ("foobar_modelc"."model_b_id" = "foobar_modelb"."id") 139663365718536 !!! The two queries are the same !!!
The expectation is that the original QuerySet is not mutated, and the two queries are different. This behavior also happens with 'prefetch_related'.
Since the QuerySet methods call 'self._clone()', and state that they return 'a new QuerySet instance', this behavior does not seem correct.