Opened 14 months ago

Last modified 13 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 14 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 13 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 13 months ago by nip3o

Failing test:

   diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py
index 63f9e97..5d70da2 100644
--- a/tests/defer_regress/tests.py
+++ b/tests/defer_regress/tests.py
@@ -144,6 +144,18 @@ class DeferRegressionTest(TestCase):
             list(SimpleItem.objects.annotate(Count('feature')).only('name')),
             list)
 
+    def test_ticket_23051(self):
+        item = Item.objects.create(value=1, name='item')
+        OneToOneItem.objects.create(item=item, name='one_to_one_item')
+
+        obj = Item.objects.only('name', 'one_to_one_item__name').get(name='item')
+
+        with self.assertNumQueries(0):
+            self.assertEqual(obj.name, 'item')
+
+        with self.assertNumQueries(0):
+            self.assertEqual(obj.one_to_one_item.name, 'one_to_one_item')
+
     def test_only_and_defer_usage_on_proxy_models(self):
         # Regression for #15790 - only() broken for proxy models
         proxy = Proxy.objects.create(name="proxy", value=42)

comment:4 Changed 13 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