Django Model for players - python

I'm working on a django website that can allow me to display some information about players and matches for a game.
There will be multiple matches and multiple players. The problem I'm having is that I'm not sure if this is what I should be doing:
class Player(models.Model):
player_id = models.IntegerField(default=0)
matches = models.ManyToMany(Match)
class Matches(models.Model):
match_id = models.IntegerField(default=0)
players = models.ManyToMany(Player)
or I should be doing:
class Player(models.Model):
player_id = models.IntegerField(default=0)
class Matches(models.Model):
match_id = models.IntegerField(default=0)
players = models.ManyToMany(Player)
A player can be in multiple matches, and a match can contain multiple players, which is why I'm a bit confused.

You should define the relation in only one of the models, so the second example is the correct one.
In the first one (you have a typo there that should be Matches by the way) you are creating two separate M2M relations between the two models that you don't want to have in your case.
On an unrelated note, you don't need to to have player_id and match_id columns as Django will automatically create id columns for your models.

The following code will solve your model structure for your project.
class TimeStamped(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Player(TimeStamped):
name = models.CharField(max_length=50)
extra_info = models.TextField()
matches = models.ManyToManyField('Match')
def __unicode__(self):
return self.name
class Match(TimeStamped):
title = models.CharField(max_length=50)
extra_info = models.TextField()
class Meta:
verbose_name_plural = 'Matches'
def __unicode__(self):
return self.title
The TimeStamped model is a good idea for every project you build. If you are using Python 3 then replace __unicode__ with __str__. Don't use plural in model names. Use verbose_name_plural, that is the convention in my opinion. It seems like you might have a problem with query players from a Match instance. Read the documentation for a detailed info on that. If you can't find that post here. Since this post is not about the querysets so I skipped that part.

Absolutely right for this scenario, ManyToMany relation is required to setup in DB.
id is the default field in Django model if you are not providing any other primary key. And ID is incremental. As per my opinion, Following models are enough to satisfy your scenario.
class Player(models.Model):
name = models.CharField(max_length=255)
class Match(modles.Model):
player = models.ManyToMany(Player, related_name="matches")
According to above model sample, you can accessing matches of one player and players who played a single match.
match = Match.objects.get(id=1)
print match.player.all() # It will print all players for match of id 1
player = Player.objects.get(id=1)
print player.matches

You definetelly have to use ManyToManyField, you can add it only to one model:
class Player(models.Model):
player_id = models.IntegerField(default=0)
matches = models.ManyToMany(Match)
class Matches(models.Model):
match_id = models.IntegerField(default=0)
After declaring models, Player objects have access to their related Matches objects in next way:
player.matches.all()
Matches objects have access to their related Player objects in next way:
match.player_set.all()
See article Many-to-many relationships, Django documentation, there are plenty of use full information of how to dial with ManyToMany relations in Django.

Related

How to make my models follow DRY principles

I have a model in which I need to represent different jobs for a labor application, for example:
from django.db import models
class PostFirstJobAd(models.Model):
fist_job_ad_title = models.CharField(max_length=225)
first_job_ad_description = models.TextField()
created_at = models.DateTimeField(auto_now=True)
class PostSecondJobAd(models.Model):
second_job_ad_title = models.CharField(max_length=225)
second_job_ad_description = models.TextField()
created_at = models.DateTimeField(auto_now=True)
class PostThirdJobAd(models.Model):
third_job_ad_title = models.CharField(max_length=225)
third_job_ad_description = models.TextField()
created_at = models.DateTimeField(auto_now=True)
Instantly you can see that I'm repeating title, description and created_at, I'm just changing field's name, it's not DRY and code is starting to smell. The reason for this is because I want to register every job separately inside django admin, so I will have clear situation inside site administration.
One way to make them DRY is to use Abstract base classes but I have a problem because from the docs:
This model will then not be used to create any database table.
Instead, when it is used as a base class for other models, its fields
will be added to those of the child class.
What will be the right approach in this case, can someone help me understand this.
Using abstract base models:
class JobAd(models.Model):
title = models.CharField(max_length=225)
description = models.TextField()
created_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class PostFirstJobAd(JobAd):
pass
class PostSecondJobAd(JobAd):
pass
class PostThirdJobAd(JobAd):
pass
This would create 3 tables. The base class JobAd does not have a table in the db.
Since you appear to have 3 different models with the exact same code, you should question whether you really need 3 different models at all. Another option is to just store them all in one table, and add another field for the "other" thing.
class JobAd(models.Model):
pos = models.CharField(max_length=100, choices=['first', 'second', 'third'])
title = models.CharField(max_length=225)
description = models.TextField()
created_at = models.DateTimeField(auto_now=True)
An integer field for pos is also possible.
First off, the abstract models might be what you need here. Depending on the business requirements, you may need to think a little harder on the architecture.
If, in fact, you do need to use abstract base classes:
class BaseJob(models.Model):
title = models.CharField(max_length=255)
# etc...
class Meta:
abstract = True
def method_1(self):
# base methods that work for instance data
Once that is defined, you can implement the base class in a concrete model. A concrete model is a model that doesn't use the abstract = True metaclass property (or proxy, etc.) like so:
class Job(BaseJob):
pass
If you need additional fields you can define them like any other model field but when you run makemigrations you'll find the fields get added in the migration generated.

Optionally retrieve related items in Django REST framework

Suppose I have these models:
class House(models.Model):
name = models.CharField(max_length=50)
# Other attributes
class Booking(models.Model):
house = models.ForeignKey(House, on_delete=models.CASCADE)
arrival_date = models.DateField()
departure_date = models.DateField()
Serializers:
class HouseSerializer(serializers.ModelSerializer):
class Meta:
model = House
fields = ('id','name')
class BookingSerializer(serializers.ModelSerializer):
class Meta:
model = Booking
fields = ('id',
'arrival_date',
'departure_date',
'house')
As you can see, bookings are associated to houses.
Users can request information about a house through "/house/:houseId", and bookings through "/booking/:bookingId".
I'd like to return all bookings related to a house when a user requests "/house/bookings", but these should NOT be returned when simply requesting "/house/bookings" as this is a relatively expensive operation and not usually needed.
I know how to make them be returned with the house, but how to make this optional. How do I do that?
First, it makes more sense (to me at least) to have your endpoint for bookings for a given house exist at /house/:houseId/bookings/ since the namespace at /house/bookings/ will already be looking for an ID.
You can also serialize the relationship between a House and Booking to display bookings for a house at the house detail endpoint. Something like:
class HouseSerializer(serializers.ModelSerializer):
bookings = BookingSerializer(many=True)
class Meta:
model = House
fields = ('id','name', 'bookings',)
But if you want another endpoint, just create a view that takes the BookingSerializer and filters the queryset by the House ID in the kwargs:
(Again, assuming your endpoint is /house/<house_id>/bookings/)
class BookingsForHouseListView(ListAPIView):
serializer_class = BookingSerializer
def get_queryset(self):
return Bookings.objects.filter(house__id=self.kwargs['house_id'])
Maybe you can do two serializers, one to the List of houses without showing the books, and another for the individual house, showing the books.
In the views you define the list serializer for the list uri, and the individual serializer for the individual uri.
Turns out, I was trying with too high-level parts of the API that restricted me more than they were helping me, I needed to do some things manually.
This answer https://stackoverflow.com/a/17763864/1582024 shows how to implement a hierarchy of resources.

(beginner) First Django Web App - models.py

I'm starting my first Django web app [after completing the Django official tutorial and Django Girls tutorial].. I'm having some trouble wrapping my head around setting up models. I have something now that works, but I feel that it is quite inefficient and I rather learn the correct way before going forward..
Starting out - When learning a new programming language, a lot of people (on the internet) advise to pick a topic/hobby you enjoy and make a project out of it. I enjoy sports a lot and wanted to recreate a virtual scoreboard, similar to ESPN or any other sports web site.
My models.py currently looks like this -
class Game(models.Model):
# start_time = models.DateTimeField()
today = models.DateField(default=date.today)
game_id = models.AutoField(primary_key=True)
game_outcome = models.CharField(max_length=8)
game_quarter = models.CharField(max_length=1)
game_clock = models.PositiveSmallIntegerField()
away_team_id = models.CharField(max_length=3)
away_team_class = models.CharField(max_length=3)
away_team_city = models.CharField(max_length=13)
away_team_name = models.CharField(max_length=12)
away_team_score = models.PositiveSmallIntegerField()
home_team_id = models.CharField(max_length=3)
home_team_class = models.CharField(max_length=3)
home_team_city = models.CharField(max_length=13)
home_team_name = models.CharField(max_length=12)
home_team_score = models.PositiveSmallIntegerField()
but I feel like this is way too many variables and not the correct way to go about it. I have also tried something like this...
class Day(models.Model):
today = models.DateField(default=date.today)
class Game(models.Model):
game_id = models.AutoField(primary_key=True)
game_outcome = models.CharField(max_length=8)
game_quarter = models.CharField(max_length=1)
game_clock = models.PositiveSmallIntegerField()
away_team_id = models.CharField(max_length=3)
away_team_score = models.PositiveSmallIntegerField()
home_team_id = models.CharField(max_length=3)
home_team_score = models.PositiveSmallIntegerField()
class Team(models.Model):
team_id = models.ForeignKey('Team')
team_class = models.CharField(max_length=3)
team_city = models.CharField(max_length=13)
team_name = models.CharField(max_length=12)
Every Day has 0 to xx amount of games. Than every game has: outcome (null or 'FINAL'), current quarter ('1' or null), current clock ('00:00' or null), away team ('CHA'), away score ('99'), home team('TOR') and home score('102'). Then I would take the team id's and compare that to the class Team. Every Team has a class (for css: 'tor'), a city ('Toronto'), and full name ('Raptors').
Still it's not sticking in my head. I can get the all the information in a python shell and output to my html/css, but I feel it's inefficient. Also, every Day has it's own html page (similar to website.com/nba/scores/20150112/) and is filled with all the games from that day.
Sorry if this is too beginner to ask; I have spent a lot of time looking for answers and finally decided to post on stackoverlow (my first question ever).
Any information or advice would be greatly appreciated.
First of all you need to understand the more ForeignKeys you use the more load you put on the database. But it also depends a lot on the views.py code as well. Second of all you don't need to use team_id as a field name if you use a ForeignKey. Just mention the class name and it will automatically create an _id for the field.
Look at the following code:
class Game(models.Model):
start_time = models.DateTimeField()
today = models.DateField(default=date.today)
game_id = models.AutoField(primary_key=True) # You don't need this line, an id field is created for EVERY model class even if you don't specify it.
game_outcome = models.CharField(max_length=8)
game_quarter = models.CharField(max_length=1)
game_clock = models.PositiveSmallIntegerField()
away_team = models.ForeignKey('Team')
home_team = models.ForeignKey('Team')
class Team(models.Model):
team_class = models.CharField(max_length=3)
city = models.CharField(max_length=13)
name = models.CharField(max_length=12)
score = models.PositiveSmallIntegerField()
You can see that I have created another class by the name of Team and put four fields on that which was repeated in your original Game class. Then I have connected the Team class to the Game class with ForeignKey. If you install SQLiteBrowser and check out the database file then you will see that the away_team field is actually the away_team_id field in the database because Django takes care of that. You don't need to create id fields, just use relations like ForeignKey, ManyToManyField, etc. Off the top of my head this is the only thing that I can suggest.
Judging by the scope of this project you will not put too much pressure on the database with too many relations, so don't worry about that now. That' it. If you have any question more specific you can ask. Cheers! :)
P.S. I am not sure about your project details so use whichever relation you see fit, be it one-to-one, many-to-one or many-to-many, etc. Read the docs for more details. :)
I think the general idea of your model approach is good enough. Nevertheless, I'd encourage you to go through Django's ORM relationships documentation. It's ok if you want to use strings as your primary key, but let Django's ORM know that by using the proper model field. If you use primary and foreign keys (relationships), your dbms will create indexes over the necessary fields, resulting in more efficient queries. Let me know if this help! Good luck with your project!
UPDATE:
It would be something like this:
class Day(models.Model):
today = models.DateField(default=date.today)
class Game(models.Model):
game_outcome = models.CharField(max_length=8)
game_quarter = models.CharField(max_length=1)
game_clock = models.PositiveSmallIntegerField()
day = models.ForeignKey(Day, on_delete=models.CASCADE)
away_team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='away_team')
away_team_score = models.PositiveSmallIntegerField()
home_team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='home_team')
home_team_score = models.PositiveSmallIntegerField()
class Team(models.Model):
team_class = models.CharField(max_length=3)
team_city = models.CharField(max_length=13)
team_name = models.CharField(max_length=12)
Notice that I omitted all id fields, since django will use one automatically created, which behaves the same as AutoField. Also notice that since Game has two references to the same class (Team), it is necessary to provide the extra parameter related_name. Mor info about it in django docs about related_name.
This way, you can do things like
game = Game.objects.find(1)
away_team_name = game.away_team.team_name
You can access the associated Team class in the away_team variable. No need to call away_team_id at all.

Storing list of objects in Django model

Is there a way in Django to have multiple objects stored and manageable (in Django admin) inside another object?
Example, I have two models: Items and RMA. The RMA may have multiple Items inside of it. Each Item is unique in the sense that it is an inventoried part, so I can't just reference the same item multiple times with foreignKey (though maybe I'm misunderstanding its use/implementation).
So for now, I have an Item model:
class Item(models.Model):
serial_number = models.CharField(max_length=200)
name = models.CharField(max_length=200)
part_number = models.CharField(max_length=200)
location = models.CharField(max_length=200)
def __unicode__(self):
return self.name
And an RMA model:
class RMA(models.Model):
number = models.AutoField(primary_key=True)
items = ?????
Ultimately I'd like to be able to maintain use of the Django admin functionality to add/remove items from an RMA if necessary, so I've been staying away from serializing a list and then deserializing on display. Any help would be much appreciated.
You're modeling a has-many relationship.
This would be modeled with a Foreign Key on Item to RMA:
class Item(models.Model):
serial_number = models.CharField(max_length=200)
name = models.CharField(max_length=200)
part_number = models.CharField(max_length=200)
location = models.CharField(max_length=200)
rma = models.ForeignKey(RMA)
def __unicode__(self):
return self.name
To make it accessible in the admin of RMA you need djangos InlineAdmin functionality.
You can find examples in the django tutorial part2.
You are effectively describing a Many-To-One relation and to do this you are going to have to add the ForeignKey reference to the Item model, not to the RMA model.
You can also add a related_name to give the RMA model an attribute that you can call.
For example:
class Item(models.Model):
rma = models.ForeignKey(RMA,related_name="items")
serial_number = models.CharField(max_length=200)
# etc...
To manage the creation of these, you'll need an InlineModelAdmin form, so your admin.py file will need to look like this:
from django.contrib import admin
class ItemInline(admin.TabularInline):
model = Item
class RMAAdmin(admin.ModelAdmin):
inlines = [
ItemInline,
]

Correctly using subclasses/proxies in django that have self referential foreign keys?

I have two classes, with a super class. In essence the two classes are concrete classes on a tree. One is a leaf, one is a branch. They share properties defined in the super class.
None of the below classes are finished. I've tried both making the superclass abstract, and the subclasses proxies. Hopefully the code below explains what I'm trying to achieve.
This is the 'super class'
class Owner(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
class Meta:
abstract=True
This is the 'leaf'
class User(Owner):
pass
This is the 'branch'.
class Group(Owner):
head = models.ForeignKey(User)
members = models.ManyToManyField(Owner,through='Membership')
This shows how a user can belong to a group by a membership.
class Membership(models.Model):
date_joined = models.DateField()
user = models.ForeignKey(Owner)
group = models.ForeignKey(Group)
My restrictions are that each user can belong to many groups (via the linker Membership). Each group can be a member of a single group.
This fails because I'm referencing Owner in both the membership as the user, and in the group members. I feel like this is the sort of thing I could solve with generics in Java, but thats not going to help me here.
I've also seen ContentTypes used for this sort of thing, but they seem too complicated for what I'm trying to do. Am I wrong? I can't figure out how to apply that paradigm to my example. I also found this question but I'm still not certain on how it should be implemented.
You can't have foreign key fields pointing to an abstract class (there is no table in the DB for an abstract class).
You'll probably need to implement self-referential foreign key for each Group to belong to zero or one group. Something like this:
class Base(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
class Meta:
abstract=True
class User(Base):
groups = models.ManyToManyField('Group', through='Membership', related_name='members')
class Group(Base):
head = models.ForeignKey(User)
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
def descendants(self, **kwargs):
qs = self.children_set.filter(**kwargs)
for group in self.children_set.all():
qs = qs | group.descendants(**kwargs)
return qs
class Membership(models.Model):
date_joined = models.DateField()
user = models.ForeignKey(User)
group = models.ForeignKey(Group)
The Base class above does nothing other than dictate that each inherited class has a name field in their respective DB table and __unicode__ method- nothing more. You could simply copy and paste the name field and __unicode__ method into User and Group and it would be functionally identical. Having a common abstract parent doesn't create any DB relationships and you can't use it to query the DB.
I can't really see any reason for using proxy classes in this situation.

Categories

Resources