Django using many-to-one relationships - python

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?

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.

Related

Django - Create model with fields derivable from other model

I have 2 Django models representing the coin domain.
The Coin has some properties and the trading Pair is based on those properties.
class Coin(models.Model):
code = models.CharField(max_length=8, primary_key=True)
name = models.CharField(max_length=32)
class Pair(models.Model):
code = models.CharField(max_length=16, primary_key=True)
name = models.CharField(max_length=64)
base_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='base_currency')
quote_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='quote_currency')
Let's add a couple of Coin instances:
first = Coin.objects.create(code="BTC", name="Bitcoin")
second = Coin.objects.create(code="USD", name="United States Dollar")
and one Pair:
Pair.objects.create(code="BTCUSD", name="Bitcoin / United States Dollar", base_currency=first, quote_currency=second)
As you can see, code and name in the Pair model can be derived from code and name in the Coin model.
To put it simple:
Pair Code = First Coin Code + Second Coin Code
Pair Name = First Coin Name + "/" + Second Coin Name
But, in this example I simply hardcoded those values and for sure this is not the best way to handle this situation.
For example: what if in the Coin model I need to change the name of an instance?
Then, I will have to manually update code and name in the Pair model, because this values are not properly binded from the Coin Model.
I believe Pair code/name must be binded/derived from the Coin model in some way.
Is there a way to do that in Django?
You might not need to store the name of your Pair since it can be infered from the references from Pair.base_currency and Pair.quote_currency.
A property on the Pair class should be enough:
class Pair(models.Model):
base_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='base_currency')
quote_currency = models.ForeignKey(Coin, on_delete=models.CASCADE, null=False, related_name='quote_currency')
#property
def code(self) -> str:
return self.base_currency.code + self.quote_currency.code
#property
def name(self) -> str:
return f'{self.base_currency.name} / {self.quote_currency.name}'

How do I relate two table to know which value is included in ManyToMany field in Django?

Hope that the title is not as confusing as I thought it would be. I currently have a table for PaymentsData:
class PaymentsData(models.Model):
match = models.CharField(max_length=30)
amount = models.DecimalField(default = 0, max_digits = 5, decimal_places = 2)
players = models.ManyToManyField(Profile, blank=True)
playerspaid = models.ManyToManyField(Profile, related_name='paid', blank=True)
datespent = models.DateField('Date Spent')
def __str__(self):
return self.match
This field is used to create matches and include the number of players that played within players section and when they paid move them to playerspaid field.
What I wanted to do is using a different table, I wanted to present all the players individually, and include the matches that they need to pay for (which we can know by fetching the players in PaymentsData above). So it should look something similar to this:
class PlayersPaymentDetails(models.Model):
player = models.OneToOneField(Profile, on_delete=models.CASCADE)
matches = models.ManyToManyField(PaymentsData, blank=True)
amountdue = models.DecimalField(default = 0, max_digits=5, decimal_places = 2)
here in the matches, it should show all the matches that the player is selected in the players field within PaymentsData and the amountdue should show how much the player owes all together.
I have tried customising the model using the save() method, however when the players gets unselected from the PaymentsData, it does not change the PlayersPaymentDetails table.
Hope someone can help, Thanks. Do let me know if that's not clear.
Why do you need another table?
You can get the matches like so:
player = Profile.objects.get(...) # get the player you want
matches = player.paymentsdata_set.all()
and amountdue:
from django.db.models import Sum
player = Profile.objects.get(...) # get the player you want
amountdue = player.paymentsdata_set.all().aggregate(amountdue=Sum('amountdue'))['amountdue']

How to add another field in connection with a ManyToManyField?

class Team(models.Model):
college = models.CharField(max_length=20)
image = models.FileField(upload_to='documents/',null=True)
def __str__(self):
return self.college
class Athletics(Match):
time = ?
player = models.ManyToManyField(Player, related_name='player')
game_level = models.CharField(max_length=256, null=True, choices=LEVEL_CHOICES) # like semi-final, final etc
game_specific = models.CharField(max_length=256,null=True, choices=EVENT_CHOICES) #like Men's Shot Put or Men's Triple Jump etc
def __str__(self):
return str(self.game_level)
I am making an Athletics Sports Model for a sports tournament. I have an existing Player Model where I have listed players names and their teams. Now as you can see, I have added player field as ManyToManyField to choose for say 4-5 players match. Now I need finishing time for each player for judging who qualifies for the next round. Can it be possible to do this in this model only? Or I have to add another model? Help me!
You need an intermediate model between Player and Athletics to record information specific to the many-to-many relationship of the two models. Please read Extra fields on many-to-many relationships.
class PlayeAthletics(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
athletics = models.ForeignKey(Athletics, on_delete=models.CASCADE)
time = models.IntegerField()
class Athletics(Match):
player = models.ManyToManyField(Player, through='PlayerAthletics')

Python/Django Trying to continually reference foreign keys in multiple classes and be able to print out information from views

I know how to reference a single foreign key but when it comes to a foreign key inside another foreign key, I'm lost. I can't think of the correct logic to make this work, which makes me think there's a special logic that applies to this.
What I've tried:
b2=[]
league = League.objects.get(name='International Collegiate Baseball Conference')
team = league.teams.all()
for b in team.curr_players.all():
b2.append(b.first_name + b.last_name)
From my models:
class League(models.Model):
name = models.CharField(max_length=50)
sport = models.CharField(max_length=15)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Team(models.Model):
location = models.CharField(max_length=50)
team_name = models.CharField(max_length=50)
league = models.ForeignKey(League, related_name="teams")
class Player(models.Model):
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=15)
curr_team = models.ForeignKey(Team, related_name="curr_players")
all_teams = models.ManyToManyField(Team, related_name="all_players")
found the answer, i had to do a for loop to iterate through what i was receiving from league.teams.all() - which was a team object and then set the iterations equal to a variable and set another iteration equal to variable.related_name.all()
b2=[]
league = League.objects.get(name='International Collegiate Baseball Conference')
team = league.teams.all()
for a in team:
players = a
for b in players.curr_players.all():
b2.append(b.first_name + b.last_name)

Getting many to many fields of many to many association in django model

I have two levels of many to many associations in django. A player can belong to one or many teams. And a team can play one or many tournaments. Given a player i want to know in which all tournaments he has played.
Following is the simplified model:
class Tournament(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
class Team(models.Model):
team_name = models.CharField(max_length=100, blank=True, null=True)
tournaments_played = models.ManyToManyField(Tournament)
class Player(models.Model):
player_name = models.CharField(max_length=100, blank=True, null=True)
belongs_to_team = models.ManyToManyField(Team)
In my views i tried the following:
pl = Player.objects.get(player_name = "Andrew Flintoff")
ts = pl.belongs_to_team()
this gives me more than one team, now for each of the team i want to know which tournaments they have played.
qs_list = []
for t in ts:
team_qs = Team.objects.get(team_name = t)
tourn = team_qs.tournaments_played.all()
qs_list.append(tourn)
and then in my context i can pass the queryset list qs_list. Is there a better/simpler way of doing it??
p1_tournaments = Tournament.objects.filter(team__player=p1)
There's an implicit lookup created for every reverse foreign key or m2m field. It's either the lowercased model class or the related_name argument, if specified.
So, essentially, that filter says get the tournaments related to teams that are related to the player, p1.

Categories