How to add another field in connection with a ManyToManyField? - python

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')

Related

Django Serialization - Partial update on nested objects

Searched around for a few hours on this and I am surprised I couldn't find an answer but here it goes.
Let's say I have the following models:
class Mission(models.Model):
mission_name = models.CharField(max_length=150)
...
class Player(models.Model):
player_name = models.CharField(max_length=150, unique = True)
state = models.CharField(max_length=150)
currentMission = models.ForeignKey(Mission,on_delete=models.SET_NULL, blank=True, null=True))
Objectives:
When creating a mission, I would like to provide the players' names that are going to participate on this mission (Names are unique). That means, when mission is created, I have to update the currentMission field of each given player. (Players already exist when mission is created)
When I try to GET a mission, I would like to see the names of the players that participate
My attempt
Class MissionSerializer(serializers.ModelSerializer):
#This is to get a list of the players that participate in this mission
players = PlayerSerializer(many=True, read_only=True)
class Meta:
model= Mission
fields = ['mission_name','players']
def create(self,validated_data):
mission = Mission.objects.create(**validated_data)
# Notice that I get the "players" data from "self.initial_data" and not from validated_data
# This is because validated_data does not have the "players" field,
# (I guess because I didn't provide all the required fields on my request for the player. I just provided the players' names )
players_data = self.initial_data['players']
#Update each player's current mission
for player_data in players_data:
qs = Player.objects.filter(player_name=player_data['player_name'])
obj = get_object_or_404(qs)
serializer = PlayerSerializer(obj, data={'currentMission': mission.id}, partial=True)
if (serializer.is_valid()):
serializer.save()
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('__all__')
def update(self, instance, validated_data):
instance.currentMission = validated_data['currentMission']
instance.save()
return instance
The above works for objective #1. However, it does not work for objective #2. That is, when I GET a mission, the list of players is not present on the result.
My question is, how could I also retrieve this list when performing GET requests?
I think that players field lacks a source. Adding a source to the field should solve your problem.
players = PlayerSerializer(many=True, read_only=True, source='player_set')
Also, I'd recommend to prefetch that players to optimize the database query.
In your view;
mission_queryset = Mission.objects.filter(...).prefetch_related('player_set')

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?
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.

Django model design for tennis league

To learn web development, I'm developing a web app to help me manage our local tennis doubles league. We play once weekly, and it works like this:
Based on their rank, players are assigned to a court each week. The four players on each court play three Sets, changing partners for each Set. A team wins a Set by winning 6 games:
Set 1: Players 1 & 4 vs Players 2 & 3
Set 2: Players 1 & 3 vs Players 2 & 4
Set 3: Players 1 & 2 vs Players 3 & 4
After we finish, I evaluate the scores and recalculate each player's new rank.
Here are my Django models:
class Event(models.Model):
event_date = models.DateField()
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Set(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
team1_player1 = models.ForeignKey(
Player,
related_name='+',
on_delete=models.CASCADE)
team1_player2 = models.ForeignKey(
Player,
related_name='+',
on_delete=models.CASCADE)
team2_player1 = models.ForeignKey(
Player,
related_name='+',
on_delete=models.CASCADE)
team2_player2 = models.ForeignKey(
Player,
related_name='+',
on_delete=models.CASCADE)
team1_games_won = models.PositiveIntegerField(default=0)
team2_games_won = models.PositiveIntegerField(default=0)
At minimum, I have a couple of concerns:
In the Set model, the Player ForeignKey attributes caused reverse
accessor clashes, so I added related_name='+'.
If later I decide to retrieve a player's Set history, it would be nice to do something like this:
>>> p = Player.objects.get(id=1)
>>> p.sets.all()
But without the reverse accessor, it's not that simple.
I can make it work, but I'm wondering if there is a better way than my Set model?
Thanks
I would consider making a team object, with many to many relationships for the players on them. This would mean you now have 6 teams (ex. red yellow green blue indigo violet) that may also help with organization. Labeling each set as team_x_player_x is hard work to remember.
This is how I would do it.
Event:
date - datefield
sets - manytomanyfield # all the sets played that day
Set:
teams - manytomanyfield
winner - foreignfield
score - textfield (6-3)
Team:
name - textfield (to simplify ex team red vs team blue)
players - manytomanyfield
Player:
user - foreignfield
mmr - integer
Now you have a clearly defined hierarchy where an event has sets, sets have teams, and teams have players. It gets rid of the annoying issue you had with the related_name as well. You can now call player.team.all() and set all the teams that player plays on. You can also get team.set.all() to get all the sets each team has played in.

Django Query including a table where no relation can be followed

i'm trying to 'join' this 4 models in a query. My starting point is a Team.id.
I am trying to get the SkillRecord into the result but i am completly lost.
class Team(models.Model):
user = models.ForeignKey(User)
id = models.IntegerField(primary_key=True, null=False, unique=True)
...
class Player(models.Model):
id = models.IntegerField(primary_key=True)
...
class Transfer(models.Model):
player = models.ForeignKey(Player)
seller = models.ForeignKey(Team, related_name='transfer_seller')
buyer = models.ForeignKey(Team, related_name='transfer_buyer')
date = models.DateTimeField()
...
class SkillRecord(models.Model):
player = models.ForeignKey(Player)
date = models.DateTimeField(default=datetime.datetime.now)
...
Here is my humble approach so far
def list_players(request, teamid):
team = get_object_or_404(Team, id=teamid)
players_transfers = Transfer.objects.filter(buyer=team).select_related('player')
I'm not really sure what would be my next step to get the SkillRecord model into the game.
I seem to lack the basic gist of those kind of problems so i will need a poke i guess.
Also, feel free to give me further ideas how to do this, i'm more or less sure i could also solve this whole Transfer thing using manytomanyfields or so.
Thanks a lot
To grab SkillRecord as well you need to add related_name:
class SkillRecord(models.Model):
player = models.ForeignKey(Player, related_name='skills')
date = models.DateTimeField(default=datetime.datetime.now)
then make the query:
qt = Transfer.objects.filter(...).select_related('player').prefetch_related('player__skills')
then retrieve them like so:
qt[0].player.skills.all()
Making some assumptions each Player has a Team so we can add.
class Player(models.Model):
team = models.ForeignKey(Team)
Then if you want the skillrecord start by there
SkillRecord.objects.filter(player__team=team)

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