Opened 22 months ago

Last modified 7 months ago

#23051 new Bug

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

Reported by: vvd 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

Description

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)

# manage.py 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 22 months ago by bmispelon

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

Hi,

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.

Thanks.

comment:2 Changed 22 months ago by nip3o

  • Owner changed from nobody to nip3o
  • Status changed from new to assigned

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

comment:3 Changed 22 months ago by nip3o

Failing test:

  • tests/defer_regress/tests.py

       diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py
    index 63f9e97..5d70da2 100644
    a b class DeferRegressionTest(TestCase): 
    144144            list(SimpleItem.objects.annotate(Count('feature')).only('name')),
    145145            list)
    146146
     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')
     150
     151        obj = Item.objects.only('name', 'one_to_one_item__name').get(name='item')
     152
     153        with self.assertNumQueries(0):
     154            self.assertEqual(obj.name, 'item')
     155
     156        with self.assertNumQueries(0):
     157            self.assertEqual(obj.one_to_one_item.name, 'one_to_one_item')
     158
    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 7 months ago by timgraham (previous) (diff)

comment:4 Changed 22 months ago by nip3o

  • Owner nip3o deleted
  • Status changed from assigned to new
  • Version changed from 1.6 to master

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