HamYam
HamYam

Reputation: 25

Django Models Design: Solo-Player OR Team with players in Game

I'm designing a Django based webinterface for a game which can be played either solo OR as a team. A game is based on points; First party to reach set number of points wins. For later statistics and displaying, points have a timestamp.

My Problem: How can I have either two Players OR two Teams in one Game? My Models look like this at the moment:

from django.db import models

# Create your models here.

class Player(models.Model):
    slug = models.SlugField(unique=True)    # will be autogenerated when inserting new Instance
    name = models.CharField(max_length=100)
    wins = models.IntegerField()
    losses = models.IntegerField()

    picture = models.ImageField(upload_to='images/player_pics')

    # games_played = wins + losses 

    def __str__(self):
        return self.name

class Team(models.Model):
    slug = models.SlugField(unique=True)
    name = models.CharField(max_length=100)
    players = models.ManyToManyField(Player)
    
    wins = models.IntegerField()    # from here on seems redundant to Player class
    losses = models.IntegerField() 

    picture = models.ImageField(upload_to='images/team_pics')

    # games_played = wins + losses 

    def __str__(self):
        return self.name


class Point(models.Model):
    val = models.IntegerField()
    timestamp = models.DateTimeField()


class Game(models.Model):
    slug = models.SlugField(unique=True)
    timestamp = models.DateTimeField()
    players = models.ManyToManyField(Player) # here should be either Team or Player
    points = models.ManyToManyField(Point)

My Idea was to implement another class like GameParty which can be either a Player or a Team but the same problem applies there. The redudant fields like wins and losses are also something I don't like.

Upvotes: 1

Views: 206

Answers (1)

Alain Bianchini
Alain Bianchini

Reputation: 4191

You don' t need to hard code wins, loses and games played, because you can obtain these values ​​with a query using foreign keys and many-to-many relationships (you can also create a dynamic property in your model to return the query to avoid repetitions). Change your models:

from django.db import models


class Player(models.Model):
    slug = models.SlugField(unique=True)
    name = models.CharField(max_length=100)
    picture = models.ImageField(upload_to='images/player_pics')

    def __str__(self):
        return self.name

class Team(models.Model):
    slug = models.SlugField(unique=True)
    name = models.CharField(max_length=100)
    players = models.ManyToManyField(Player)
    picture = models.ImageField(upload_to='images/team_pics')

    def __str__(self):
        return self.name


class Point(models.Model):
    player = models.ForeignKey(Player, on_delete=models.PROTECT, related_name='points') # You need to associate the player with the point
    val = models.IntegerField()
    timestamp = models.DateTimeField()


class Game(models.Model):
    slug = models.SlugField(unique=True)
    timestamp = models.DateTimeField()
    players = models.ManyToManyField(Player, related_name='games')
    points = models.ManyToManyField(Point)

Now for example to obtain games played by a player you can write this query:

player = Player.objects.get(id=1)
games_played = player.games.count()

Or with a dynamic property (this property is not inserted in the database but it is evaluated at each call, so you don' t need to update it):

class Player(models.Model):
    # Your fields and methods
    @property
    def games_played(self):
        return self.games.count()

To write queries take reference from the documentation. If you want to associate also teams with games, you can create an additional table or use a generic relation.

Upvotes: 0

Related Questions