Opened 11 months ago

Closed 11 months ago

Last modified 3 days ago

#34612 closed Bug (fixed)

QuerySet.only() doesn't work with select_related() on a reverse OneToOneField relation.

Reported by: Ian Cubitt Owned by: Simon Charette
Component: Database layer (models, ORM) Version: 4.2
Severity: Release blocker Keywords:
Cc: Simon Charette Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

On Django 4.2 calling only() with select_related() on a query using the reverse lookup for a OneToOne relation does not generate the correct query.
All the fields from the related model are still included in the generated SQL.

Sample models:

class Main(models.Model):
    main_field_1 = models.CharField(blank=True, max_length=45)
    main_field_2 = models.CharField(blank=True, max_length=45)
    main_field_3 = models.CharField(blank=True, max_length=45)


class Secondary(models.Model):
    main = models.OneToOneField(Main, primary_key=True, related_name='secondary', on_delete=models.CASCADE)
    secondary_field_1 = models.CharField(blank=True, max_length=45)
    secondary_field_2 = models.CharField(blank=True, max_length=45)
    secondary_field_3 = models.CharField(blank=True, max_length=45)

Sample code:

Main.objects.select_related('secondary').only('main_field_1', 'secondary__secondary_field_1')

Generated query on Django 4.2.1:

SELECT "bugtest_main"."id", "bugtest_main"."main_field_1", "bugtest_secondary"."main_id", "bugtest_secondary"."secondary_field_1", "bugtest_secondary"."secondary_field_2", "bugtest_secondary"."secondary_field_3" FROM "bugtest_main" LEFT OUTER JOIN "bugtest_secondary" ON ("bugtest_main"."id" = "bugtest_secondary"."main_id")

Generated query on Django 4.1.9:

SELECT "bugtest_main"."id", "bugtest_main"."main_field_1", "bugtest_secondary"."main_id", "bugtest_secondary"."secondary_field_1" FROM "bugtest_main" LEFT OUTER JOIN "bugtest_secondary" ON ("bugtest_main"."id" = "bugtest_secondary"."main_id")

Change History (7)

comment:1 by Mariusz Felisiak, 11 months ago

Cc: Simon Charette added
Severity: NormalRelease blocker
Summary: QuerySet.only() regression on Django 4.2 with select_related() on a reverse OneToOneField relationQuerySet.only() doesn't work with select_related() on a reverse OneToOneField relation.
Triage Stage: UnreviewedAccepted

Thanks for the report!

Regression in b3db6c8dcb5145f7d45eff517bcd96460475c879.
Reproduced at 881cc139e2d53cc1d3ccea7f38faa960f9e56597.

comment:2 by Simon Charette, 11 months ago

Owner: changed from nobody to Simon Charette
Status: newassigned

comment:3 by Simon Charette, 11 months ago

Has patch: set

comment:4 by Mariusz Felisiak, 11 months ago

Triage Stage: AcceptedReady for checkin

comment:5 by Mariusz Felisiak <felisiak.mariusz@…>, 11 months ago

Resolution: fixed
Status: assignedclosed

In 2cf76f2d:

Fixed #34612 -- Fixed QuerySet.only() crash on reverse relationships.

Regression in b3db6c8dcb5145f7d45eff517bcd96460475c879.

Thanks Ian Cubitt for the report.

This also corrected test_inheritance_deferred2() test which was
previously properly defined and marked as an expected failure but was
then wrongly adjusted to mask the lack of support for per-alias
deferral that was fixed by #21204.

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 11 months ago

In 7383864:

[4.2.x] Fixed #34612 -- Fixed QuerySet.only() crash on reverse relationships.

Regression in b3db6c8dcb5145f7d45eff517bcd96460475c879.

Thanks Ian Cubitt for the report.

This also corrected test_inheritance_deferred2() test which was
previously properly defined and marked as an expected failure but was
then wrongly adjusted to mask the lack of support for per-alias
deferral that was fixed by #21204.

Backport of 2cf76f2d5d1aa16acfadaf53db3d30128a34b088 from main

comment:7 by nessita <124304+nessita@…>, 3 days ago

In 83f54782:

Fixed #35356 -- Deferred self-referential foreign key fields adequately.

While refs #34612 surfaced issues with reverse one-to-one fields
deferrals, it missed that switching to storing remote fields would break
self-referential relationships.

This change switches to storing related objects in the select mask
instead of remote fields to prevent collisions when dealing with
self-referential relationships that might have a different directional
mask.

Despite fixing #21204 introduced a crash under some self-referential
deferral conditions, it was simply not working even before that as it
aggregated the sets of deferred fields by model.

Thanks Joshua van Besouw for the report and Mariusz Felisiak for the
review.

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