Opened 3 years ago

Last modified 17 months ago

#23051 new Bug

QuerySet.only() fail to work with reverse o2o relationships

Reported by: Vladimir Dmitriev Owned by:
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords: orm only reverse relationship OneToOneField
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Specifying a field from reverse relationship model in the .only() queryset method have no effect on compiled query:

# sample models
class Person(models.Model):
    name = models.CharField(max_length=64)

class PersonExtra(models.Model):
    bio = models.TextField()
    information = models.TextField()
    person = models.OneToOneField(Person)

# shell
>>> from testapp.models import Person
>>> print Person.objects.all().only('name').query
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person"
>>> print Person.objects.all().select_related('personextra').only('name', 'personextra__bio').query # expected table join and personextra__bio to be loaded
SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person"

defer() method works fine:

>>> print Person.objects.all().select_related('personextra').defer('personextra__information').query
SELECT "testapp_person"."id", "testapp_person"."name", "testapp_personextra"."id", "testapp_personextra"."bio", "testapp_personextra"."person_id" FROM "testapp_person" LEFT OUTER JOIN "testapp_personextra" ON ( "testapp_person"."id" = "testapp_personextra"."person_id" )

Change History (4)

comment:1 Changed 3 years ago by Baptiste Mispelon

Triage Stage: UnreviewedAccepted


I can indeed reproduce this.

Currently, Person.objects.only('name', 'personextra__bio') is accepted by returns the wrong query. If supporting that use case is not possible, it should at least raise an error instead of silently doing the wrong thing.


comment:2 Changed 3 years ago by Niclas Olofsson

Owner: changed from nobody to Niclas Olofsson
Status: newassigned

Will try to at least make a test for this during EP14.

comment:3 Changed 3 years ago by Niclas Olofsson

Failing test:

  • tests/defer_regress/

       diff --git a/tests/defer_regress/ b/tests/defer_regress/
    index 63f9e97..5d70da2 100644
    a b class DeferRegressionTest(TestCase): 
    144144            list(SimpleItem.objects.annotate(Count('feature')).only('name')),
    145145            list)
     147    def test_ticket_23051(self):
     148        item = Item.objects.create(value=1, name='item')
     149        OneToOneItem.objects.create(item=item, name='one_to_one_item')
     151        obj = Item.objects.only('name', 'one_to_one_item__name').get(name='item')
     153        with self.assertNumQueries(0):
     154            self.assertEqual(, 'item')
     156        with self.assertNumQueries(0):
     157            self.assertEqual(, 'one_to_one_item')
    147159    def test_only_and_defer_usage_on_proxy_models(self):
    148160        # Regression for #15790 - only() broken for proxy models
    149161        proxy = Proxy.objects.create(name="proxy", value=42)
Last edited 17 months ago by Tim Graham (previous) (diff)

comment:4 Changed 3 years ago by Niclas Olofsson

Owner: Niclas Olofsson deleted
Status: assignednew
Version: 1.6master

I looked in to this, and it seems that at least SQLCompiler.deferred_to_columns (and all related methods called before then) works as intended in this case. However, I will not be able to solve this, even if I believe that it should not be unsolvable.

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