abstract = True
- powoduje, że django nie stworzy tabelki pod ten model, ta tabelka musi wcześniej istnieć jeśli pozostałe tabelki odwołują się do niej poprzez klucz obcy.
EDIT:
Ogólnie utrudniasz sobie pracę.
Widać, że łatwiej Ci jest gdy masz stan gry określony poza bazą, a mimo to próbujesz określić logikę na djangowych modelach.
Opieranie logiki bezpośrednio na djangowych modelach jest OK, gdy robisz coś trywialnego, i gdzie świadomie olewasz dobre zasady dotyczące obiektowości, aby poprzez django skrót ułatwić sobie interakcje bazy z pozostałymi rzeczami jakie django oferuje.
W przypadku gdy masz więcej logiki to warto odejść od tego i logikę zapisać ją tak w oderwaniu od bazy.
Implementując szachy nie musisz specjalnie polegać na obiektowości. Ta gra ma zamknięte reguły, więc za bardzo nie skorzystasz na obiektowości i potencjalnych rozszerzeniach jakie mógłbyś w oparciu o klasy czy obiekty zrobić.
Lepiej zrób sobie funkcje, które przyjmują planszę jako argument i które na jej podstawie wykonują zadania. Nie jest to w 100% rozwiązanie najlepsze, ale na tym etapie nie potrzebujesz więcej.
W przypadku django warto uważać, bo stan gry, nawet taki który nie musi być utrwalony, będzie Ci giną w aplikacji co przeładowanie kodu przez django. Musiałbyś co przeładowanie robić odtwarzać stanu planszy z powrotem z bazy (na podstawie ruchów). Tu masz przykład jak dopisać logikę, która się wykona przy przeładowaniu https://stackoverflow.com/a/43593959
Tu dodam, że póki nie robisz optymalizacji z potrzeby to uważaj, aby przy wdrożeniu ograniczyć liczbę instancji tej aplikacji do 1, bo przy większej liczbie instancji aplikacji requesty mogą trafić nie tam gdzie wstępnie zakładasz, a w rezultcie operacje się mogą pomieszać.
Co do modeli to warto wprowadzić 2 zmiany:
- aby model Ruch powiązać z modelem odnoszącym się do konkretnej potyczki, bo inaczej ruchy z jednej potyczki zleją Ci się z ruchami z drugiej.
- nie warto robić ForeginKey do każdej figury z osobna, nie warto łączyć ruchu z pionkiem bo pionek w trakcie gry zaciera swoją wcześniejszą pozycję, a jak ją usuniesz to wraz z nią przy CASCADE znikną w bazie wszystkie wpisy powiązane z figurą. Lepiej ruch wiązać z typem figury, a wtedy możesz uprościć i informacje o figurach trzymać w jednej tabelce. Albo też skorzystać z jeszcze większego uproszczenia jakie django wprowadza czyli choicesz choices: https://docs.djangoproject.com/en/4.2/ref/models/fields/#django.db.models.Field.choices To podejście pozwoli Ci uniknąć tworzenia tabelek, więc jest szybko i łatwo, ale z drugiej strony to niekorzystnie wpłynie na samą integralność danych (innymi słowy poza aplikacją django, wszyscy ludzie pracujący mający styk z bazą mogą wpisać głupoty w do tabelki z ruchami, a łaza i tak to łyknie). Dobrym podejściem jest postrzeganie bazy nie jako głupiego składowiska danych, a systemu który zabiega (w granicach rozsądku) o poprawność wprowadzonych danych, czy ich aktualizacje.
funkcje jakie mógłbyś mieć to:
- game = loads_game(game_id) - wczytuje grę z bazy (gra niech zawiera informację o planszy i o tym, który gracz wykonał ostatnio ruch), w środku tej funkcji robisz wczytanie wszystkich ruchów, a potem nakładasz je na czystą planszę; z czasem jak się projekt rozwinie to możesz zrobić optymalizację, aby stanu gry nie wczytywać z dziennika, ale całościowo np. z bazy podręcznej takiej jak redis
- is_allowed_move(move) - ocenia czy ruch jest dopuszczalny, zwraca wartość typu bool
- save_move(game_id, move) - gdy wiesz, że ruch został przyjęty wołasz save_move, aby zapisać zmianę (ta część nie jest specjalnie obiektowa, ale też nie ogranicza Ci pola do dalszego rozwinięcia)