0

I am creating a project in Django for a multiplayer battleship game, I am trying to set up my database so I can record games, players and user actions, here is the app/model.py code

from django.db import models


# Create your models here.
class Player(models.Model):
    username = models.CharField(max_length=10,primary_key=True)
    password = models.CharField(max_length=10)


class GameBoard(models.Model):
    size = models.IntegerField(default=10)
    state = models.CharField(max_length=500,default='')

class Game(models.Model):
    game_id = models.AutoField(primary_key=True)
    player1 = models.ForeignKey(Player,related_name='player1',blank = True,null=True,on_delete=models.SET_NULL)
    player2 = models.ForeignKey(Player,related_name='player2',blank = True,null=True,on_delete=models.SET_NULL)
    board = models.ForeignKey(GameBoard,related_name='game_board',on_delete=models.CASCADE)

    def __str__(self):
        return f'Game: {self.game_id}, player1: {self.player1}, player2: {self.player2}, board {self.board}'

class Action(models.Model):
    GAME_ACTIONS = (
        ('a', 'Attack'),
        ('s', 'Surrender'),
    )
    player_action = models.ForeignKey(Player,related_name='player_action',null=True,on_delete=models.SET_NULL)
    action = models.CharField(max_length=3, choices=GAME_ACTIONS)
    game = models.ForeignKey(Game,related_name='played_in',on_delete=models.CASCADE)

Then I run makemigrations and migrate to update the database. Finally I try to test the code by using manage.py shell:

from battleship.models import *

p1 = Player('Alice','password1')
p1.save()
p2 = Player('Bob','password')
p2.save()

b = GameBoard()
b.save()

g = Game(player1 = p1,player2 = p2,board = b)
g.save()

When I run this code I receive the following error: django.db.utils.IntegrityError: FOREIGN KEY constraint failed. I also tried to save a game with no players:

g = Game(player1 = None,player2 = None,board = b)
g.save()

The previous code is able to execute without error, I also checked the saved object on the database and it actually saved it correctly.

I assume that the issue is with p1 and p2, however I don't understand why, since board is a foreign key as well. I am assuming this depends on the null=True in the Player model, however I don't see the problem with that parameter being there (if a player is deleted I want to update the existing game names to null instead of deleting on cascade).

Cristian
  • 53
  • 6
  • 1
    I think it is conflicting with the related name in `Game` model. Did you try by changing either the related name of `player1` and `player2` or the attribute name itself? – Sadan A. Jul 20 '21 at 11:49
  • I tried and it seems to have helped, now the error is OperationalError: table battleship_game has no column named p1_id (Yes I did migrate after the change) – Cristian Jul 20 '21 at 11:53
  • Can you post your updated model code? – Sadan A. Jul 20 '21 at 11:58
  • 1
    Also, in your above example you are not creating the player objects correctly. While creating the objects you have to use keyword arguments. Like you are using for `Game`. – Sadan A. Jul 20 '21 at 11:59
  • game_id = models.AutoField(primary_key=True) p1 = models.ForeignKey(Player,related_name='player1',blank = True,null=True,on_delete=models.SET_NULL) p2 = models.ForeignKey(Player,related_name='player2',blank = True,null=True,on_delete=models.SET_NULL) board = models.ForeignKey(GameBoard,related_name='game_board',on_delete=models.CASCADE) – Cristian Jul 20 '21 at 12:00
  • I tried using the keyword arguments, but it didn't make any change – Cristian Jul 20 '21 at 12:23

1 Answers1

1

The related_name in this case is what is used by the Player model to reference objects of the Game model. It is confusing in this case as the Player model can be referenced by either the Game.player_1 or Game.player_2 fields. A ManyToMany field called players may make more sense here. Otherwise change the value of related_name to "game_1" and "game_2" or similar.

This question explains related_name well

Django documentation on related_name

axevalley
  • 335
  • 2
  • 10
  • Ok, I found out taht he database was not working correctly even when trying to flush it and resetting the migration folder (probably out of sync?). I created another app with the same code and the suggestions and it worked in both ways you suggested, thanks! – Cristian Jul 20 '21 at 12:46