Barbatos_Best_Bot
Barbatos_Best_Bot

Reputation: 33

Django using many-to-one relationships

I'm completely new to Django web development and I'm having some issues using many to one relationships. I'm trying to complete a coding exercise in which I must develop a database for a game club where there will be a member list and a match list. the member list will store information pertaining to the member (eg. name, date they joined the club, matches won, matches lost, average score) and the match list will store data about each recorded match (eg. who player 1 and player 2 are, what date the match took place and what each players score was). What I was going to do was to use the many to one relationship to link multiple matches to a member and then have the match outcomes be information used to calculate Member information.

members/models.py:

from django.db import models


class Member(models.Model):
    name = models.CharField(max_length=30)
    match_wins = models.IntegerField()
    match_losses = models.IntegerField()
    date_joined = models.CharField(max_length=10)
    average = models.IntegerField()
    high_score = models.IntegerField()

matches/models.py:

from django.db import models
from members.models import Member


class Match(models.Model):
    player1 = models.ForeignKey(Member, on_delete=models.CASCADE)
    player2 = models.ForeignKey(Member, on_delete=models.CASCADE)
    p1_score = models.IntegerField()
    p2_score = models.IntegerField()
    winner = ???(models.Member_id maybe?)
    loser = ???
    date = models.CharField(max_length=10)

As an example, how would I get match_wins in the Member class to be calculated via searching the matches attributed to member_id x and incrementing a value as per each win attributed to his id?

Same goes for the average value in the Member class, how would I query the matches attributed to member_id x again and increment a value per match played, sum the scores per each match and divide the result by the incremented value to get the average?

How would I do the comparison of each score attributed to member_id x to find the highest?

Also, on the Match side of things how do I get p1_score tied to player1 (same for player2) and get winner to compare the scores of player 1 and 2, then give the highest scoring player the win and the other player the loss?

Any help on this would be greatly appreciated as I am completely lost. Would it be easier to have Member and Match switched so that Member has the ForeignKey of a Match?

Upvotes: 3

Views: 3640

Answers (1)

Cory Madden
Cory Madden

Reputation: 5193

class Member(models.Model):
    name = models.CharField(max_length=30)
    match_wins = models.IntegerField()
    match_losses = models.IntegerField()
    date_joined = models.CharField(max_length=10)
    average = models.IntegerField()
    high_score = models.IntegerField()


class Match(models.Model):
    player1 = models.ForeignKey(Member, related_name='games_as_player1', on_delete=models.CASCADE)
    player2 = models.ForeignKey(Member, related_name='games_as_player2', on_delete=models.CASCADE)
    p1_score = models.IntegerField()
    p2_score = models.IntegerField()
    winner = models.ForeignKey(Member, related_name='games_won')
    loser = models.ForeignKey(Member, related_name='games_lost')
    date = models.CharField(max_length=10)


player = Member.objects.get(pk=1)
player.games_won.count()

You also need to add related_name to the player1 and player2 fields so you can have multiple ForeignKeys to the same object.

Additionally, I would actually change the relationship to a Many To Many with possible additional information stored on the intermediary table, such as which player they were. This would remove the need for redundant fields. So maybe something like this:

class Member(models.Model):
    name = models.CharField(max_length=30)
    date_joined = models.CharField(max_length=10)
    matches = models.ManyToManyField(Match, through='MemberMatch')

class MemberMatch(models.Model):
    player = models.ForeignKey(Member)
    match = models.ForeignKey(Match)
    score = models.IntegerField()
    won = models.BooleanField()

class Match(models.Model):
    date = models.CharField(max_length=10)

And you could perform easy queries to get all the information I've removed from the classes.

Upvotes: 1

Related Questions