Opened 5 years ago
Last modified 5 years ago
#30796 closed Bug
Chaining select_related mutates original QuerySet. — at Version 1
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 (last modified by )
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") 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") 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") !!! 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.