2010-06-24 14 views
7

Poniższy kod jest podany:Django modelu podklasy: Get podklasy przez odpytywanie nadklasę

class BaseMedium(models.Model): 
    title = models.CharField(max_length=40) 
    slug = models.SlugField() 

class A(BaseMedium): 
    url = models.URLField() 

class B(BaseMedium): 
    email = models.EmailField() 

teraz chcę zapytać każdą BaseMedium.

b = BaseMedium.objects.all() 

Jak wydrukować wszystkie informacje, w tym pola podklas, nie wiedząc, jaki jest typ podklasy?

b[0].a byłoby wydrukowanie informacji jeśli b[0] jest rzeczywiście związane z wystąpieniem A ale jeśli jest to związane z B byłoby wydrukować DoesNotExist wyjątku.

Ma to sens, ale chciałbym mieć wspólną zmienną lub metodę, która zwraca powiązany obiekt.

Może mój układ bazy danych nie jest zbyt dobry, aby zapytać w ten sposób, więc byłbym zadowolony, gdybyś polecił lepszy układ.

Myślałem o użyciu GenericForeignKey

class Generic(models.Model): 
    basemedium = models.ForeignKey('BaseMedium') 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    object = generic.GenericForeignKey('content_type', 'object_id') 

ale to rozwiązanie wydaje się być skomplikowana i myślę, że macie lepsze rozwiązania.

Odpowiedz

2

Jedynym sposobem, aby to zrobić, jest jawne zapisanie w modelu podstawowym, jaki to jest. Więc pole derived_type (lub cokolwiek innego) na BaseMedium i ustaw go na zapis. Następnie możesz mieć metodę get_derived_type:

def get_derived_type(self): 
    if self.derived_type == 'A': 
     return self.a 
    elif self.derived_type == 'B': 
     return self.b 

i tak dalej.

1

Dziękuję panu. Roseman za twoją odpowiedź. Rozwinąłem twój pomysł nieco dalej. Oto co wymyśliłem:

def related_object(self, default_pointer_name='_ptr'): 
     models = [A,B] #models 
     object = None 

     argument = '%s%s' %(self.__class__.__name__.lower(), default_pointer_name) 
     query = { argument : self} 

     for model in models: 
      try: 
       object = model.objects.get(**query) 
      except model.DoesNotExist: 
       pass 
      else: 
       return object 

     if object == None: 
      raise RelatedObjectException 
     return object 

Jest to metoda stosowana przez BaseMedium.

+0

Powinieneś być ostrożny z tym. Jeśli masz 1000 rekordów do pobrania z DB, zostanie to wykonane w jednym SELECT, ale wtedy będzie 1000 pojedynczych wyborów, aby uzyskać podtyp dla każdego obiektu BaseMedium. W każdym razie nie wiem, jak to zrobić. Używam czegoś podobnego, co powoduje wiele dodatkowych zapytań db ... – dzida

+1

Strzelaj, masz rację. Własny sql może być opcją ... Dziwne jest to, że nie rozumiem, jak to nie jest powszechny problem ze znanym rozwiązaniem. – rotrotrot

3

Należy sprawdzić rozwiązanie posted by Carl Meyer jakiś czas temu. Wewnętrznie wykorzystuje podejście ContentType, ale bardzo elegancko je enkapsuluje.

Wskazuje również na alternatywne i bardziej wydajne rozwiązanie, które nie wymaga przechowywania dodatkowego pola w bazie danych, ale działa tylko w przypadku bezpośrednich zajęć dla dzieci. Jeśli masz kilka poziomów dziedziczenia, pierwsze rozwiązanie jest lepsze.