Oto mój model:
class GroupedModels(models.Model):
other_model_one = models.ForeignKey('app.other_model')
other_model_two = models.ForeignKey('app.other_model')
Zasadniczo chcę, other_model
aby była wyjątkowa w tej tabeli. Oznacza to, że jeśli istnieje rekord, w którym other_model_one
znajduje się id 123
, nie powinienem zezwalać na tworzenie kolejnego rekordu z other_model_two
id jako 123
. Chyba mogę to zmienić clean
, ale zastanawiałem się, czy django ma coś wbudowanego.
Używam wersji 2.2.5 z PSQL.
Edycja: To nie jest wspólna sytuacja. Jeśli dodam rekord za pomocą other_model_one_id=1
i innych other_model_two_id=2
, nie powinienem być w stanie dodać kolejnego rekordu za pomocą other_model_one_id=2
i innychother_model_two_id=1
python
django
django-models
Pittfall
źródło
źródło
Odpowiedzi:
Wyjaśniam tutaj kilka opcji, może jedna z nich lub ich kombinacja może być dla Ciebie przydatna.
Nadrzędny
save
Twoje ograniczenie jest regułą biznesową, możesz zastąpić
save
metodę, aby zachować spójność danych:Zmień projekt
Podaję próbkę łatwą do zrozumienia. Załóżmy, że ten scenariusz:
Teraz chcesz uniknąć drużyny, która rozegra mecz ze sobą, a także drużyna A może zagrać tylko raz z drużyną B (prawie twoje zasady). Możesz przeprojektować swoje modele jako:
ManyToManyField.symmetrical
Wygląda to na symetryczny problem, django może sobie z tym poradzić. Zamiast tworzyć
GroupedModels
model, po prostu stwórz pole ManyToManyField na sobieOtherModel
:Właśnie to ma wbudowane django dla tych scenariuszy.
źródło
match_id
zawarłem to na zasadzie wyjątków, aby umożliwić drużynom rozgrywać nieograniczoną liczbę meczów. Wystarczy usunąć to pole, aby ponownie ograniczyć odtwarzanie.To niezbyt satysfakcjonująca odpowiedź, ale niestety prawda jest taka, że nie da się zrobić tego, co opisujesz, za pomocą prostej wbudowanej funkcji.
To, co opisałeś
clean
, działałoby, ale musisz uważać, aby ręcznie to wywołać, ponieważ myślę, że jest wywoływane automatycznie tylko podczas korzystania z ModelForm. Możesz być w stanie utworzyć złożone ograniczenie bazy danych ale będzie ono działać poza Django i będziesz musiał obsługiwać wyjątki bazy danych (co może być trudne w Django, gdy jest w trakcie transakcji).Może istnieje lepszy sposób na uporządkowanie danych?
źródło
Jest już świetna odpowiedź od Dani Herrera , jednak chciałbym ją dalej rozwinąć.
Jak wyjaśniono w drugiej opcji, rozwiązaniem wymaganym przez PO jest zmiana projektu i wdrożenie dwóch unikalnych ograniczeń parami. Analogia z meczami koszykówki ilustruje problem w bardzo praktyczny sposób.
Zamiast meczu koszykówki używam przykładu z grami piłkarskimi (lub piłkarskimi). Mecz piłki nożnej (który nazywam
Event
) jest rozgrywany przez dwie drużyny (w moich modelach jest drużynaCompetitor
). Jest to relacja wiele do wielu (m:n
), zn
ograniczeniem do dwóch w tym konkretnym przypadku, zasada jest odpowiednia dla nieograniczonej liczby.Oto jak wyglądają nasze modele:
Wydarzeniem może być:
Teraz musimy rozwiązać problem z pytania. Django automatycznie tworzy tabelę pośrednią między modelami z relacją wiele do wielu, ale możemy użyć niestandardowego modelu i dodać kolejne pola. Nazywam ten model
Participant
:ManyToManyField
Posiada opcjęthrough
, która pozwala nam określić pośredni model. Zmieńmy to w modeluEvent
:Unikatowe ograniczenia teraz automatycznie ograniczyć liczbę konkurentów na razie do dwóch (bo tam są tylko dwie role: Start i Visitor ).
W konkretnym wydarzeniu (meczu piłki nożnej) może być tylko jedna drużyna gospodarzy i tylko jedna drużyna gości. Club (
Competitor
) może występować jako drużyna gospodarzy lub drużyna gości.Jak zarządzamy teraz tymi wszystkimi rzeczami w adminie? Lubię to:
Dodaliśmy
Participant
jako wbudowany wEventAdmin
. Kiedy tworzymy nowyEvent
, możemy wybrać zespół gospodarzy i zespół gości. Opcjamax_num
ogranicza liczbę zgłoszeń do 2, dlatego nie można dodać więcej niż 2 drużyn na wydarzenie.Można to zmienić dla różnych przypadków użycia. Powiedzmy, że nasze imprezy to zawody pływackie, a zamiast domu i gościa mamy ścieżki od 1 do 8. Po prostu zmieniliśmy
Participant
:Dzięki tej modyfikacji możemy mieć to wydarzenie:
tytuł: FINA 2019, 50-metrowy finał mężczyzn w stylu grzbietowym,
Uczestnicy:
// i tak dalej na linii 5 do linii 8 (źródło: Wikipedia
Pływak może pojawić się tylko raz w upale, a tor może być zajęty tylko raz w upale.
Umieszczam kod w GitHub: https://github.com/cezar77/competition .
Ponownie wszystkie kredyty trafiają do Dani Herrera. Mam nadzieję, że ta odpowiedź zapewni czytelnikom pewną wartość dodaną.
źródło