5

Otrzymuję dziwny błąd, próbując wybrać wiele powiązanych relacji OneToOneField, np. w przypadku, gdy pole docelowe jest podklasą wnuka. Chciałbym, aby ktoś pomógł mi zrozumieć, co się dzieje (lub potwierdzić, że jest to błąd w Django).Django select_related z polami określonymi przerwami w wielu relacjach jeden do jednego

Ilustracja:

# models.py 
from django.db import models 

class A(models.Model): 
    pass 

class B(A): 
    pass 

class C(B): 
    pass 

dość proste, prawda? Teraz otwieram powłokę Django z czystą bazą danych:

>>> C().save() 
>>> A.objects.select_related('b__c') 
[] 

Czekaj, co? Dlaczego ten zestaw zapytań jest pusty? Szybkie sprawdzenie poprawności:

>>> A.objects.select_related('b')[0].b.c 
<C: C object> 

Dlaczego więc wywołanie select_related nie działa? Cóż, obejrzyj to:

>>> A.objects.select_related('b__c').__iter__().next() 
... 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/query.py", line 107, in _result_iter 
    self._fill_cache() 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/query.py", line 772, in _fill_cache 
    self._result_cache.append(self._iter.next()) 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/query.py", line 273, in iterator 
    for row in compiler.results_iter(): 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 680, in results_iter 
    for rows in self.execute_sql(MULTI): 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 725, in execute_sql 
    sql, params = self.as_sql() 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 58, in as_sql 
    self.pre_sql_setup() 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 29, in pre_sql_setup 
    self.fill_related_selections() 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 661, in fill_related_selections 
    used, next, restricted, new_nullable) 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 617, in fill_related_selections 
    chain = opts.get_base_chain(f.rel.to) 
    File "/opt/webapps/asdf/lib/python2.6/site-packages/django/db/models/options.py", line 452, in get_base_chain 
    % model._meta.module_name,) 
TypeError: 'b' is not an ancestor of this model 
>>> 

Czy to błąd Django, czy też nie rozumiem czegoś?

+1

Biorąc pod uwagę ciszę, zgłosiłem błąd: https://code.djangoproject.com/ticket/16572 – rfrankel

+0

dostałem dokładnie ten sam problem. dziwne zachowanie, naprawdę wygląda jak django. –

Odpowiedz

0

dodałem name = Charfield do A i prowadził następujące testy w łupinach:

>>> a = A(name='a_object') 
>>> a.save() 
>>> b = B(name='b_object') 
>>> b.save() 
>>> c = C(name='c_object') 
>>> c.save() 

>>> A.objects.all() 
[<A: A object>, <A: A object>, <A: A object>] 
>>> B.objects.all() 
[<B: B object>, <B: B object>] 
>>> C.objects.all() 
[<C: C object>] 

>>> A.objects.select_related('b__c') 
[] 
>>> A.objects.select_related('b__c').__iter__().next() 
Traceback .... 
    ... 
    TypeError: 'b' is not an ancestor of this model 

>>> d = A.objects.select_related('B__C') 
>>> for item in d: 
...  print item.name 
... 
a_object 
b_object 
c_object 

>>> test = A.objects.select_related('B__C').__iter__().next() 
>>> test.name 
u'a_object' 

wiem, że to nie jest odpowiedź, a ja nie wiem, co o tym sądzić. Ale w zasadzie znalazłem, że mała litera nie wydaje się oznaczać niczego bez pól w modelach.

+0

Małe litery to pola używane do downcastingu obiektu do instancji podklasy. Na przykład, A.objects.get (id = 2) .b zwróci obiekt B o identyfikatorze = 2, jeśli istnieje, i podnieść wyjątek w inny sposób. Podobnie, A.objects.get (id = 3) .b.c zwróci obiekt C (zakładając, że istnieje). Wysłany przeze mnie bilet został faktycznie potwierdzony i zaakceptowany, więc uważam, że jest to błąd. – rfrankel

0

Mam ten sam problem, ale trochę inna struktura modelu

class A(models.Model): 
    b = models.ForeignKey(B) 
.... 
class B(models.Model): 
.... 
class C(models.Model): 
    b = models.OneToOneField(B) 
    d = models.OneToOneField(D) 
.... 
class D(models.Model): 
.... 

Więc kiedy piszę

A.objects.select_related('b__c__d').all() 

Nie widzę wszystko - przedmioty, tylko te, w których C nie jest zerowe. Jednak, gdy piszę

A.objects.select_related('b__c').all() 

Django ORM zwraca mi wszystko przedmiotów, w tym tych, gdzie C jest null.

Wydaje mi się, że błąd jest dla mnie, select_related nie powinien działać jako filtr.