What is Football game statistics Django Model logic? - python

I am creating an app that visualizes football game statistics on Django. I take data from https://fbref.com/ as a CSV file. I have a python script that cleans data and create data frame with ['Player', 'Shots', 'SCA', 'Touches', 'Pass', 'Carries', 'Press', 'Tackled', 'Interceptions', 'Blocks'] columns (I can add Team name, Game Date, Home/Away or whatever).
And now I need to create models to store this data. I don't know what models do I need.
Option 1 (only one model):
class GameStats(models.Model):
date = models.DateField()
team_name = models.CharField(max_length=20)
home_away = models.CharField(max_length=20, choices=HOME_AWAY)
name = models.CharField(max_length=20)
number = models.IntegerField()
age = models.IntegerField()
shots = models.IntegerField()
SCA = models.IntegerField()
touches = models.IntegerField()
passes = models.IntegerField()
But it will give one Row of data. Technically, I can group rows by Team_name and Date.
Option 2:
from django.db import models
class Team(models.Model):
name = models.CharField(max_length=200)
league = models.CharField(max_length=200)
def __str__(self):
return self.name
class Player(models.Model):
name = models.CharField(max_length=200)
number = models.IntegerField()
age = models.IntegerField()
team = models.ForeignKey(Team, related_name='team', on_delete=models.CASCADE)
def __str__(self):
return self.name
class HomeTeam(models.Model):
team = models.ForeignKey(Team, related_name='home_team', on_delete=models.CASCADE)
players = models.ManyToManyField(Player)
def __str__(self):
return self.team
class AwayTeam(models.Model):
team = models.ForeignKey(Team, related_name='away_team', on_delete=models.CASCADE)
players = models.ManyToManyField(Player)
def __str__(self):
return self.team
class Game(models.Model):
title = models.CharField(max_length=200)
homeTeam = models.OneToOneField(HomeTeam, on_delete=models.CASCADE)
awayTeam = models.OneToOneField(AwayTeam, on_delete=models.CASCADE)
def __str__(self):
return self.title
In Option 2 I can understand where to put Game statistics and a list of the players.
Would be great if someone could write proper models. I really stack!

There is no one way to do it, so every answer you get for this question is going to be opinionated. That being said, for my personal preference, I would prefer the first modal approach as it is simple and has all the data in one place. I don't see a point of separating the columns into different database tables unless you know these different subset of columns are going to be used in some other models later down the line. Even then, you can always link the whole model with a ForeignKey to the new model and only use the data that you need.
Another reason I prefer the first approach is that the data does not have many columns, so dividing it into many smaller parts is making it complicated for no reason. You will be querying the database more in second approach, and later down the line, it may become difficult to keep track of things. But that is my opinion, so take it with a grain of salt.

Related

how to copy data from model to another model in Django after filtering?

here is the models:
class Rooms(models.Model):
name=models.CharField(max_length=100)
image=models.URLField()
max_person=models.CharField(max_length=100)
office=models.CharField(max_length=200)
status=models.CharField(max_length=200)
cost=models.CharField(null=True,max_length=250)
roomId=models.CharField(max_length=100,null=True)
Address= models.CharField(max_length=100,null=True)
def __str__(self):
return str(self.name)
class Available_Rooms(models.Model):
users=models.ForeignKey(Rooms,on_delete=models.CASCADE)
name=models.CharField(max_length=100)
image=models.URLField()
max_person=models.CharField(max_length=100)
office=models.CharField(max_length=200)
status=models.CharField(max_length=200)
cost=models.CharField(null=True,max_length=250)
roomId=models.CharField(max_length=100,null=True)
Address= models.CharField(max_length=100,null=True)
def __str__(self):
return str(self.name)
at model "rooms" there is 100 objects (rooms)
and what I want filter it and list rooms that have maxperson = 4
availablity= Rooms.objects.filter(maxperson="4").all()
and want to to copy the rooms details to the other model "Available_Rooms"
any idea how that can be done?
many thanks in advance
and want to to copy the rooms details to the other model Available_Rooms.
Please don't: it makes no sense to do that: you are introducing data duplication, which is an antipattern. This means that if you now want to change for example the name of a Room, you need to modify both the Rooms and the Available_Rooms. This will thus introduce a lot of extra logic to keep the rooms in sync.
What you can for example do is add a BooleanField that determines if the room is available, with:
class Room(models.Model):
name = models.CharField(max_length=100)
image = models.URLField()
max_person = models.IntegerField()
office = models.CharField(max_length=200)
status = models.CharField(max_length=200)
cost = models.IntegerField(null=True)
room_id = models.CharField(max_length=100,null=True)
address = models.CharField(max_length=100)
available = models.BooleanField(default=False)
def __str__(self):
return str(self.name)
Then you can for example make all rooms available that have as max_person=4 with:
Room.objects.filter(max_person=4).update(available=True)
Note: normally a Django model is given a singular name, so Room instead of Rooms.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: room_id instead of roomId.

Get max value from a set of rows

This question is in relation to project 2 of the cs50 course which can be found here
I have looked at the following documentation:
Django queryset API ref
Django making queries
Plus, I have also taken a look at the aggregate and annotate things.
I've created the table in the template file, which is pretty straight forward I think. The missing column is what I'm trying to fill. Image below
These are the models that I have created
class User(AbstractUser):
pass
class Category(models.Model):
category = models.CharField(max_length=50)
def __str__(self):
return self.category
class Listing(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
initial_bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date_created = models.DateField(auto_now=True)
def __str__(self):
return self.title
class Bid(models.Model):
whoDidBid = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
list_item = models.ForeignKey(Listing, default=0, on_delete=models.CASCADE)
bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now=True)
def __str__(self):
return_string = '{0.whoDidBid} {0.list_item} {0.bid}'
return return_string.format(self)
This is the closest I could come to after a very long time. But the result I get is just the number 2. Ref image below
Listing.objects.filter(title='Cabinet').aggregate(Max('bid'))
Where 'Cabinet' is a Listing object that I have created. And placed two bids on them.
So the question is, how do I get the Maximum bid value(i.e. 110 for this case) for a particular listing? Using the orm. I think if I used a raw sql query, I could build a dict, send it to the template with the queryset. Then while looping through the queryset, get the value for the key, where the key is the name of the listing or something along those lines. Nah, I would like to know how to do this through the ORM please.
Here's answer #1
Bid.objects.filter(list_item__title='Cabinet').prefetch_related('list_item').aggregate(Max('bid'))
What happens when you try this (sorry, I don't have any objects like this to test on):
Bid.objects.values(list_item__title).prefetch_related('list_item').annotate(Max('bid'))

How do I create a method in django models that returns the sum of a field in that same model?

I'm new to Django and I have two models set up like this currently. I want to calculate, in the Climber model, that returns the total points that climber has earned by accessing the climbs_completed field. How can I go about doing this? In other words, how do I sum up the points for each Climb in climbs_completed? Is there a better way to do this besides writing a method? Thank you in advance!
class Climb(models.Model):
name = models.CharField(max_length=20, default='')
grades = [('v'+str(i),'v'+str(i))for i in range(0,13)]
grade = models.CharField(max_length=3, choices=grades, default='v-1')
weeks = [(i,i)for i in range(1,13)]
week = models.IntegerField(choices=weeks, default=0)
points = models.IntegerField(default=0)
def __str__(self):
return self.name
class Climber(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
grades = [('v'+str(i),'v'+str(i))for i in range(0,13)]
highest_grade = models.CharField(max_length=3, choices=grades, default='v0')
team = models.ForeignKey(Team, null=True, on_delete=models.SET_NULL)
climbs_completed = models.ManyToManyField(Climb, blank=True)
def __str__(self):
return self.user.username
# for each climbs_completed, sum up the points
def total_score(self):
pass
You can use Sum and add the total climb points as annotated value like this:
from django.db.models import Sum
climbers = Climber.objects.annotate(total_score=Sum('climbs_completed__points'))
print(climbers.values('pk', 'total_score'))
Or you can use aggregation in the total_score method, like this:
class Climber(models.Model):
...
def total_score(self):
return self.climbs_completed.aggregate(total_score=Sum('points'))['total_score']
First method is more efficient if you want to get values from bunch of climbers and do it in one database hit.

Django calculation based on calculated value

I need your help once more. I am working on a project for my wargaming group. It is a simple ranking site. So we have players, they participate in tournaments and get points. I got to the point where I am able to assign players to tournaments, assign place they took at the tournament to their name.
Now I have to calculate points. Algorithm is simple, but I have problems passing a value from Tournament model to Ranking. Each Tournament has a calculated rating (based on other things, mostly bigger tournament, bigger rating) and in other models, I was unable to use it and need your help with it. On top of that, it would be awesome if changing a rating value in Tournament would force an update of all dependent calculations.
So we have models like that:
class Player(models.Model):
class Meta:
name = models.CharField(max_length=50)
nicname = models.CharField(max_length=50,blank=True)
army = models.CharField(max_length=50)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
class Tournament(models.Model):
class Meta:
name = models.CharField(max_length=100)
date = models.DateTimeField('date')
player_num = models.IntegerField
points = models.FloatField(default=1000.00)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
And then I have a ranking model of this kind:
class TournamentStandings(models.Model):
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
player_place = models.FloatField
In admin.py I do calculations for TournamentAdmin:
fields = ['name', 'date', 'player_num', 'points', 'get_rating']
def get_rating(self, obj):
return obj.points / 100.00
And now I would like to make calculation for TournamentStandingsAdmin:
def player_points(self, obj):
return (obj.tournament.player_num/obj.player_place)* obj.tournament.get_rating
But the result is an error
'Tournament' object has no attribute 'get_rating'
So my guess is my calculated get_rating is not a true model field but how to work around that?
as #Daniel suggested you need to add get_rating method to your Tournament model.
class Tournament(models.Model):
name = models.CharField(max_length=100)
date = models.DateTimeField('date')
player_num = models.IntegerField
points = models.FloatField(default=1000.00)
....
def get_rating(self):
return obj.points / 100.00
After that you can call the method with a Tournament object as follows:
obj.tournament.get_rating

django database structure for a gym members workout management

i would like to develop a django management app for a small gym.
we have a list of members
each member could have 1 or more card
each card could have 1 or more workout
each workout could have 1 or more exercise
each exercise has the following fields:
exercise name (can be choose from a list of exercise names),
series number (can be choose from a list of series),
repetition number (can be choose from a list of repetition),
execution mode (can be choose from a list of executions),
rest time (can be choose from a list of executions).
Here is my possibile implementation of models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Member(models.Model):
#Member data
name = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
#Contact
email = models.EmailField(blank=True, null=True)
phone = models.CharField(max_length=50, blank=True, null=True)
#Body
birthday = models.DateField(blank=True, null=True)
height = models.IntegerField(blank=True, null=True)
weigth = models.IntegerField(blank=True, null=True)
#Trainer notes
trainer = models.ForeignKey(User, limit_choices_to={'is_staff': True, 'is_superuser': False}, blank=True, null=True)
note = models.CharField(max_length=160, blank=True, null=True)
#Registration status
registration = models.DateField(auto_now_add=True)
expiration = models.DateField(blank=True, null=True)
card = models.OneToOneField('Card')
def __str__(self):
return u'%s %s' % (self.surname, self.name)
class Card(models.Model):
number = models.IntegerField()
#Card status
card_creation = models.DateField(auto_now_add=True)
card_expiration = models.DateField(blank=True, null=True)
workout = models.ForeignKey('Workout')
def __str__(self):
return u'%s' % (self.number)
class Workout(models.Model):
number = models.IntegerField()
exercise = models.ForeignKey('Exercise')
def __str__(self):
return u'%s' % (self.number)
class Exercise(models.Model):
name = models.ForeignKey('Name')
series = models.ForeignKey('Serie')
repetitions = models.ForeignKey('Repetition')
executions = models.ForeignKey('Execution', blank=True, null=True)
rest = models.ForeignKey('Rest')
def __str__(self):
return u'%s' % (self.name)
class Name(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return u'%s' % (self.name)
class Serie(models.Model):
serie = models.CharField(max_length=50)
def __str__(self):
return u'%s' % (self.serie)
class Repetition(models.Model):
repetition = models.IntegerField()
def __str__(self):
return u'%s' % (self.repetition)
class Execution(models.Model):
execution = models.CharField(max_length=50)
def __str__(self):
return u'%s' % (self.execution)
class Rest(models.Model):
rest = models.IntegerField()
def __str__(self):
return u'%s' % (self.rest)
I'm not sure if this works as described. Could you please suggest a possible implementation?
At the end I would like to have only one view with all data: member, card, workout... so the staff user can modify the user and the linked workout card) is it possible with admin.py or do I need a custom admin?
That looks pretty good, and like Samidh T said in the comments you should open up a dev server with sqlite and play around with it. See what's working what's not. That's the best thing you could do.
However, since you asked, here are a couple notes to bear in mind:
"each member could have 1 or more card" - Then why is you card field in Memeber a OneToOne? Wouldn't it make more sense to do a ForeignKey (essentially a ManyToOne) field for Card linking it to member?
"each card could have 1 or more workout" - If you have a ForeignKey from card to workout, then you are actually doing the opposite of what you described, you're doing a Many (cards) for One (workout). But maybe this is what you want? Or maybe you actually want it to be a ManyToManyField? Because each workout probably has different cards and vice-versa. I really can't tell what's the best fit here, but it's something you might want to think over.
"each workout could have 1 or more exercise" Same as with the point before.
I see that every field in your exercise is a ForeingKey. Now again - this is isn't a bad choice or idea, but you should consider what this entails, and consider replacing it with a ManyToMany or, if one of the fields is a static list (i.e. you have a limited list of available names that you know won't change in the future drastically) then you can use a CharField with option choices=.
I can't exactly tell you "this is bad", "this is good", it is a very project-subjective thing, but I hope my few tips helped you in some way. In the end, it all boils down to what you need. If you find yourself confused, I suggest reading a little about table relationships in SQL and how they work.
Django is fantastic for realizing complex relationships, but using it without learning a little bit SQL before can be confusing sometimes because you only see the end result and hardly ever look at the tables themselves.

Categories

Resources