2010-05-30 14 views
7

Czy wybrana_zależna praca dla relacji GenericRelation, czy istnieje rozsądna alternatywa? W tej chwili Django robi pojedynczy sql wywołuje dla każdego elementu w moim querysecie, a ja chciałbym tego uniknąć używając czegoś podobnego do select_related.Django: select_related and GenericRelation

class Claim(models.Model): 
    proof = generic.GenericRelation(Proof) 


class Proof(models.Model): 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

Ja wybierając kilka zastrzeżeń, i chciałbym powiązane Dowody, które mają zostać zainstalowane zamiast zapytaliśmy indywidualnie.

Odpowiedz

16

Nie ma wbudowanego sposobu, aby to zrobić. Ale opublikowałem technikę symulowania select_related na ogólnych relacjach on my blog. Zawartość


Blog podsumować:

_content_object_cache pole Django Możemy użyć aby zasadniczo tworzyć własne select_related stosunków generycznych.

generics = {} 
for item in queryset: 
    generics.setdefault(item.content_type_id, set()).add(item.object_id) 

content_types = ContentType.objects.in_bulk(generics.keys()) 

relations = {} 
for ct, fk_list in generics.items(): 
    ct_model = content_types[ct].model_class() 
    relations[ct] = ct_model.objects.in_bulk(list(fk_list)) 

for item in queryset: 
    setattr(item, '_content_object_cache', 
      relations[item.content_type_id][item.object_id]) 

Tutaj mamy wszystkich typów zawartości używanych przez relacje w queryset i zestaw odrębnych identyfikatorów obiektów dla każdego z nich, a następnie użyć wbudowanego w in_bulk metody menedżera dostać wszystko typy zawartości: od razu w miłym, gotowym do użycia słowniku z kluczem identyfikacyjnym. Następnie wykonujemy jedną kwerendę dla każdego typu zawartości, ponownie za pomocą in_bulk, aby uzyskać cały rzeczywisty obiekt .

Na koniec wystarczy ustawić odpowiedni obiekt w polu _content_object_cache elementu źródłowego. Powodem, dla którego to robimy, jest to, że jest to atrybut, który sprawdziłby Django i zapełnił, jeśli jest wymagany, jeśli wywołałeś bezpośrednio x.content_object. Przez wstępne wypełnienie , upewniamy się, że Django nigdy nie będzie musiał wywoływać indywidualnego wyszukiwania - w efekcie wprowadzamy rodzaj select_related() dla ogólnych relacji.

3

można użyć .extra funkcji(), aby ręcznie wyodrębnić pola:

Claims.filter(proof__filteryouwant=valueyouwant).extra(select={'field_to_pull':'proof_proof.field_to_pull'}) 

The .filter() zrobi dołączyć The .extra() będzie ciągnąć pole. proof_proof to nazwa tabeli SQL dla modelu Proof. Jeśli potrzebujesz więcej niż jednego pola, określ każde z nich w dyktafonie.