2010-05-14 31 views
12

mam 2 modele w moim kodu django:dostać kluczy obcych obiektów w jednym zapytaniu - Django

class ModelA(models.Model): 
    name = models.CharField(max_length=255) 
    description = models.CharField(max_length=255) 
    created_by = models.ForeignKey(User) 

class ModelB(models.Model): 
    category = models.CharField(max_length=255) 
    modela_link = models.ForeignKey(ModelA, 'modelb_link') 
    functions = models.CharField(max_length=255) 
    created_by = models.ForeignKey(User) 

Say MODELA ma 100 rekordów, z których wszystkie mogą lub nie mogą mieć linki do ModelB

teraz mówią, że chcą uzyskać listę każdego rekordu MODELA wraz z danymi z ModelB

zrobiłbym:

list_a = ModelA.objects.all() 

Następnie, aby uzyskać dane dla ModelB musiałbym zrobić

for i in list_a: 
    i.additional_data = i.modelb_link.all() 

Jednak ten uruchamia kwerendę na każdej instancji i. W ten sposób można uruchomić 101 zapytań.

Czy istnieje sposób, aby uruchomić to wszystko w zaledwie jednym zapytaniu. Lub co najmniej mniej niż 101 zapytań.

Próbowałem wstawić ModelA.objects.select_related().all(), ale wydawało się, że nie ma to żadnego wpływu.

Dzięki

Odpowiedz

7

Jak mówi Ofri, select_related działa tylko na forward stosunków, nie odwrócić te.

Nie ma wbudowanego sposobu na automatyczne śledzenie odwrotnych relacji w Django, ale zobacz my blog post, aby uzyskać technikę racjonalnie wydajną. Podstawową ideą jest uzyskanie wszystkich powiązanych obiektów dla każdego elementu naraz, a następnie powiązanie ich ręcznie z ich pokrewnym przedmiotem - dzięki czemu możesz to zrobić w 2 zapytaniach zamiast w n + 1.

2

Django ORM jest dobrą rzeczą, ale niektóre niektóre rzeczy lepiej robić ręcznie. Możesz zaimportować kursor połączenia i wykonać raw sql w pojedynczym zapytaniu.

from django.db import connection 
cur=connection.cursor() 
cur.execute(query) 
rows = cur.fetchall() 

zapytanie powinno wyglądać (MySQL)

SELECT * FROM appname_modela INNER JOIN appname_modelb ON appname_modela.id=appname_modelb.modela_link_id 
+0

Wiem, że przy korzystaniu z surowego sql nie otrzymujesz zwróconego obiektu, więc czy znasz jakiś sposób przekonwertowania wyników na obiekt Django – John

1

Powodem .select_related() nie działa, jest to, że .select_related() służy do naśladowania kluczy obcych. Twoja ModelA nie ma klucza obcego do Modelu B. ModelB, który ma klucz obcy do ModelA. (więc instancja ModelA może mieć wiele instancji ModelB powiązanych z tym).

Można to wykorzystać, aby zrobić to w 2 zapytaniami, a nieco kodu Pythona:

list_b = ModelB.objects.all() 
list_a = ModelA.objects.all() 
for a in list_a: 
    a.additional_data = [b for b in list_b if b.modela_link_id==a.id] 
+1

Dzięki za to. Czy są jakieś problemy z wydajnością? – John

Powiązane problemy