Search code examples
pythondjangopostgresqlmodelone-to-one

Django OneToOneField Structure


I have been researching and looking through all the docs but I am still a bit confused, I think maybe because there are multiple ways to use the OnToOneField.

I have 4 models, Pregame, Ingame, Postgame and Game. And I want 'Game' to contain the other three models.

As of right now it looks like this...

    class Pregame(models.Model):
        game_id = models.CharField(max_length=10)
        other fields...

        def __str__(self):
            return str(self.game_id)

    class Ingame(models.Model):
        game_id = models.CharField(max_length=10)
        other fields...

        def __str__(self):
            return str(self.game_id)

    class Postgame(models.Model):
        game_id = models.CharField(max_length=10)
        other fields...

        def __str__(self):
            return str(self.game_id)

    class Game(models.Model):
        game_id = models.CharField(max_length=10)
        pregame = models.OneToOneField(
            Pregame, on_delete=models.CASCADE, null=True)
        ingame = models.OneToOneField(
            Ingame, on_delete=models.CASCADE, null=True)
        postgame = models.OneToOneField(
            Postgame, on_delete=models.CASCADE, null=True)

        def __str__(self):
            return str(self.game_id)

I am using OnToOne because each Game will only have one Pregame, Ingame and Postgame and the other three models will only belong to one Game.

I have a couple questions I am confused about.

Will I be able to have a Game object if one of the other model objects doesn't exist yet? Like if there is a Pregame but no Ingame or Postgame, will Game still exist with just Pregame inside of it? I seen a couple videos where they did a default='{}', is that what I should be doing?

Each model has game_id and that is how I am connecting them all together into the'Game' object. Is there a OneToOneField option like game_id=game_id so the 'Game' model will automatically link all the models together or would I still have to do that separate?

Thank you for your help and knowledge.


Solution

  • First of all, you don't have to set game_id on the *game entities. You can just add related_name:

    class Game(models.Model):
        game_id = models.CharField(max_length=10)
        pregame = models.OneToOneField(
            Pregame, on_delete=models.CASCADE, null=True, related_name="game")
        ingame = models.OneToOneField(
            Ingame, on_delete=models.CASCADE, null=True, related_name="game")
        postgame = models.OneToOneField(
            Postgame, on_delete=models.CASCADE, null=True, related_name="game")
    
    class Pregame(models.Model):
        other fields...
    
        def __str__(self):
            return str(self.game_id)
    

    Will I be able to have a Game object if one of the other model objects doesn't exist yet? Like if there is a Pregame but no Ingame or Postgame, will Game still exist with just Pregame inside of it? I seen a couple videos where they did a default='{}', is that what I should be doing?

    Yes, a Game object can exist even without a *game, as you added null=True. You should use a default when your model does not accept null/empty values.

    Each model has game_id and that is how I am connecting them all together into the'Game' object. Is there a OneToOneField option like game_id=game_id so the 'Game' model will automatically link all the models together or would I still have to do that separate?

    Once you create such a model, you have access via the Game entity. For example from going to pregame to postgame:

    postgame = pregame.game.postgame