2012-03-21 12 views
10

Załóżmy, że mamy następujące modele.Django OneToOneField - w którym modelu powinienem go umieścić?

class A(Model): pass 
class B(Model): pass 

Wtedy nie ma różnicy pomiędzy:

W modelu A: b = OneToOneField(B, related_name=A.__name__)

i

w modelu B: a = OneToOneField(A, related_name=B.__name__)

Więc jakie pytania powinien zadać sobie decydować czy umieścić OTO w jednym modelu czy innym. Mam na myśli, jak ma-a, is-a i tak dalej.

Odpowiedz

1

Myślę, że w przypadku pola OneToOne, prawidłową odpowiedzią jest to, że nie ma znaczenia, to po prostu zależy od tego, który model ma więcej sensu odnosić się do drugiego.

+0

Cóż, to jest pytanie.Jak mogę się dowiedzieć, co jest bardziej sensowne? Czasami nie ma absolutnie żadnej różnicy i oba sposoby są równie możliwe. – aemdy

+0

W takich przypadkach jest to całkowicie zależne od Ciebie. Nie sądzę, że istnieje ostateczna odpowiedź. – Brandon

7

OneToOneField s to naprawdę tylko w dwóch celach: 1) dziedziczenie (Django używa ich do jej realizacji MTI) lub 2) przedłużenie nieedytowalnym modelu (jak stworzenie UserProfile dla User).

W tych dwóch scenariuszach oczywiste jest, który model OneToOneField jest kontynuowany. W przypadku dziedziczenia chodzi o dziecko. W przypadku rozszerzenia przechodzi do jedynego modelu, do którego masz dostęp.

W przypadku bardzo nietypowych wyjątków każde inne użycie jednego z nich powinno zostać połączone w jeden model.

+0

Świetna odpowiedź Chris. – Brandon

+0

Co z blokowaniem tabel? Gdybyśmy mieli oddzielić określone dane (takie jak tabela płac z tabeli pracowników), moglibyśmy użyć 'select_for_update' na tabeli Employee bez blokowania informacji o zarobkach. Poprawny? – grokpot

23

W rzeczywistości istnieje różnica w tym, gdzie umieścić pole jeden-do-jednego, ponieważ usuwanie zachowuje się inaczej. Podczas usuwania obiektu wszelkie inne obiekty, które mają relacje jeden-do-jednego odwołujące się do tego obiektu, zostaną usunięte. Jeśli zamiast tego usuniesz obiekt zawierający jedno do jednego (tzn. Odwoła się do innych obiektów, ale inne obiekty nie odwołują się do niego), żadne inne obiekty nie zostaną usunięte.

Na przykład:

class A(models.Model): 
    pass 

class B(models.Model): 
    a = models.OneToOneField(A) 

Jeśli usuniesz, domyślnie B zostaną usunięte, jak również (choć można to zmienić poprzez modyfikację on_delete argumentu na OneToOneField Podobnie jak ForeignKey). Usunięcie B nie spowoduje usunięcia A (chociaż możesz zmienić to zachowanie przez przesłonięcie metody delete() na B).

Powrót do początkowego pytania ma-a przeciw a-a, jeśli A ma B, B powinno mieć jedno-do-jednego pole (B powinno istnieć tylko jeśli A istnieje, ale A może istnieć bez B).

0

Nawiasem mówiąc, to potrzebne OneToOneField zapobiec okrągły zależności (wykorzystania spadku)

Model A: 
    ... 
    current_choice = models.ForeignKey(B) 

Model B: 
    ... 
    parent = models.ForeignKey(A) 

Oznacza to, A B musi być zdefiniowana. Nie jest to dobra konwencja bazy danych do ładowania. Zamiast zrobiłem:

Model A: 
    ... 

Model B: 
    ... 
    parent = models.ForeignKey(A) 

Model C: 
    parent = models.OneToOneField(A) 
    current_choice = models.ForeignKey(B) 

W odniesieniu do przykładu z documentation, można również mieć czyste zapytań jak: p1.restaurant.place.restaurant.place ... To jest szaleństwo.

+0

Dlaczego nie zdawałeś sobie sprawy z tego zachowania, po prostu używając * related_name * na kluczu obcym? Tak więc w Modelu A możesz zrobić 'current_choice = models.ForeignKey (B, related_name = 'parent')', a następnie na każdym wystąpieniu B ('b = B.objects.first()') możesz zrobić 'b.parent ', aby pobrać powiązany obiekt A. – Kim

+0

Cóż, 'related_name' niekoniecznie jest jeden do jednego, ale przez większość czasu jest używane jako zapytanie setowe, więc musisz sprawdzić liczbę itp. Powyższy przykład jest raczej bezpośrednim zapytaniem, ponieważ został zmuszony do uzyskania pojedynczego wyniku tylko. – hurturk