Opened 6 years ago

Closed 6 years ago

#19064 closed Bug (duplicate)

select_related doesn't work for reverse one-to-one with inheritance

Reported by: Piotr Czachur Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Docs say…

You can also refer to the reverse direction of a OneToOneField in the list of fields passed to select_related — that is, you can traverse a OneToOneField back to the object on which the field is defined. Instead of specifying the field name, use the related_name for the field on the related object.

How to reproduce

# myapp/
class Dam(models.Model):
    name = models.CharField(max_length=32) 

class Animal(models.Model):
    nickname = models.CharField(max_length=32) 

class Beaver(Animal):
    dam = models.OneToOneField(Dam, related_name='beaver')
    favourite_meal = models.CharField(max_length=32) 
# myapp/fixtures/initial_data.yaml

- model: myapp.Dam
  pk: 1
    name: Hoover 

- model: myapp.Animal
  pk: 1
    nickname: Harold

- model: myapp.Beaver
  pk: 1
    dam: 1
    favourite_meal: spagetti

# /tmp/mypro$ python2.7 shell

In [1]: from mypro.myapp.models import *

In [2]: Beaver.objects.select_related('dam')
Out[2]: [<Beaver: Beaver object>]

In [3]: Dam.objects.select_related('beaver')
Out[3]: []

In [4]: len(Dam.objects.select_related('beaver'))
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (494, 0))

AttributeError                            Traceback (most recent call last)
/tmp/mypro/django/core/management/commands/shell.pyc in <module>()
----> 1 len(Dam.objects.select_related('beaver'))

/tmp/mypro/django/db/models/query.pyc in __len__(self)
     87                 self._result_cache = list(self._iter)
     88             else:
---> 89                 self._result_cache = list(self.iterator())
     90         elif self._iter:
     91             self._result_cache.extend(self._iter)

/tmp/mypro/django/db/models/query.pyc in iterator(self)
    298             if fill_cache:
    299                 obj, _ = get_cached_row(row, index_start, db, klass_info,
--> 300                                         offset=len(aggregate_select))
    301             else:
    302                 # Omit aggregates in object creation.

/tmp/mypro/django/db/models/query.pyc in get_cached_row(row, index_start, using, klass_info, offset)
   1457                 for rel_field, rel_model in rel_obj._meta.get_fields_with_model():
   1458                     if rel_model is not None:
-> 1459                         setattr(rel_obj, rel_field.attname, getattr(obj, rel_field.attname))
   1460                         # populate the field cache for any related object

   1461                         # that has already been retrieved

AttributeError: 'Dam' object has no attribute 'nickname'

Change History (2)

comment:1 Changed 6 years ago by Piotr Czachur

Patch from #13781 fixes this issue.

comment:2 Changed 6 years ago by Simon Charette

Resolution: duplicate
Status: newclosed

Marking as duplicate of #13781.

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