﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
35376	Prefetched data not used when combining prefetch_related() and only()	Michael Schwarz	nobody	"I think I found a simple case combining `prefetch_related()` and `only()`, where  prefetched data isn't used when it should.

See the following model with a `Restaurant` being a `Building`, and a `Building` being part of a `City`. (replace `Building` with `Business` if it bugs you that a building can only contain a single restaurant 🙃, I noticed too late):

{{{#!python
from django.db.models import DO_NOTHING
from django.db.models import ForeignKey
from django.db.models import Model
from django.db.models import OneToOneField
from django.db.models import TextField

class City(Model):
    name = TextField()

class Building(Model):
    city = ForeignKey(City, on_delete=DO_NOTHING)

    street_name = TextField()
    street_no = TextField()

class Restaurant(Model):
    building = OneToOneField(Building, on_delete=DO_NOTHING)

    name = TextField()
}}}

I'm trying to build a query set of buildings with some of its attributes deferred using `only()`, and the associated restaurants and cities being prefetched. In the following parametrized `pytest` test case, only the last instance is exhibiting the issue, the other 3 seem to work as I would expect.

The test case creates an instance of each model, runs the query (`list(...)`), and then accesses the `restaurant` attribute, which should be prefetched in every case. The test case check that the access does not generate an additional query using `django_assert_num_queries()` from `pytest-django`.

{{{#!python
import pytest

from myproject.models import Building
from myproject.models import Restaurant
from myproject.models import City


@pytest.mark.parametrize('qs', [
    Building.objects.prefetch_related(""restaurant"", ""city""),
    Building.objects.only(""street_name"").prefetch_related(""restaurant""),
    Building.objects.only(""street_name"").prefetch_related(""city"", ""restaurant""),
    Building.objects.only(""street_name"").prefetch_related(""restaurant"", ""city"")
])
def test_repro(db, django_assert_num_queries, qs):
    Restaurant.objects.create(
        name="""",
        building=Building.objects.create(
            city=City.objects.create(name=""""), street_name="""", street_no=""""
        ),
    )

    result = list(qs)

    with django_assert_num_queries(0):
        result[0].restaurant
}}}

The first 3 instances of the test above succeed, the last one fails:

{{{
$ venv/bin/pytest test_repro.py
[...]

    @pytest.mark.parametrize('qs', [
        Building.objects.prefetch_related(""restaurant"", ""city""),
        Building.objects.only(""street_name"").prefetch_related(""restaurant""),
        Building.objects.only(""street_name"").prefetch_related(""city"", ""restaurant""),
        Building.objects.only(""street_name"").prefetch_related(""restaurant"", ""city"")
    ])
    def test_repro(db, django_assert_num_queries, qs):
        Restaurant.objects.create(
            name="""",
            building=Building.objects.create(
                city=City.objects.create(name=""""), street_name="""", street_no=""""
            ),
        )

        result = list(qs)

>       with django_assert_num_queries(0):

[...]

E               Failed: Expected to perform 0 queries but 1 was done (add -v option to show queries)
}}}

I've created a [https://github.com/Feuermurmel/only_prefetch_related_repro minimal project on GitHub] documenting the exact setup, including all package versions.

AFAICT, in each case above, `restaurant` should be prefetched, and the attribute access should not generate an additional access. Only when `only()` is used, another related model is also prefetched, and that other model is mentioned _after_ `restaurant` in the call to `prefetch_related()`, the prefetched data for `restaurant` isn't used.

Running macOS 12.7.4, Python 3.12.2 and Django 4.2.11.
"	New feature	closed	Database layer (models, ORM)	4.2	Normal	duplicate		Michael Schwarz Simon Charette	Unreviewed	0	0	0	0	0	0
