Opened 5 years ago

Last modified 4 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.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top