Issue with Django foreign key assignment - python

I have a series of related models. Country -> League -> Team -> Player. The model works fine relating country to league and league to team, but the team id is different as teams play in more than one competition. To deal with this I've added a ref column with an id for each team. I would like to use this ref column as the Foreign Key in my player model but I'm getting errors when I try to parse the data to the Postgres database.
I've tried using to_field and unique=True but still end up with an error. I've taken a look around but haven't found a solution yet.
Here is my models code:
from django.conf import settings
from django.db import models
from django.utils import timezone
import datetime
class Country(models.Model):
objects = models.Manager()
name = models.CharField(max_length=50,default="TBA")
id = models.IntegerField(primary_key=True,default=0)
def __str__(self):
return self.name
def __unicode__(self):
return u'%s' % self.name
class League(models.Model):
objects = models.Manager()
name = models.CharField(max_length=100,default="TBA")
id = models.IntegerField(primary_key=True,default=0)
country = models.ForeignKey(Country,on_delete=models.CASCADE)
def __str__(self):
return self.name
def __unicode__(self):
return u'%s' % self.name
class Team(models.Model):
objects = models.Manager()
name = models.CharField(max_length=100,default="TBA")
id = models.IntegerField(primary_key=True,default=0)
league = models.ForeignKey(League,on_delete=models.CASCADE)
ref = models.IntegerField(default=0)
def __str__(self):
return self.name
def __unicode__(self):
return u'%s' % self.name
class Player(models.Model):
objects = models.Manager()
name = models.CharField(max_length=64)
id = models.IntegerField(primary_key=True)
first_name = models.CharField(max_length=64,default="Unknown")
last_name = models.CharField(max_length=64,default="Unknown")
nationality = models.CharField(max_length=64,default="Unknown")
date_of_birth = models.DateField(default = datetime.date.today)
position = models.CharField(max_length=64, default="Unknown")
team_ref =models.ForeignKey(Team,to_field="ref",on_delete=models.CASCADE)
def __str__(self):
return self.name

IMHO, I think you model design is bit wrong. You should make Team to League relation as ManyToMany Field. So that, a Team can be assigned to multiple Leagues. If you want to maintain different Squads for different Tournaments, then you should create a new Model Named Squads and use it as through, and make a many to many relation to that Squads Model from Player. For example:
class Team(models.Model):
# other fields
league = models.ManyToManyField(League, through="Squad")
class Squad(models.Model):
team = models.ForeignKey(Team)
league = models.ForeignKey(League)
class Player(models.Model):
squad = models.ManyToManyField(Squad)

Related

How do you use a Custom Model Manager method for a related Many-to-Many model field?

I am working on a small project, mostly for learning, and I am running into an issue with accessing expected custom model manager methods on some related M2M type models. The application I am trying to implement is a travel calculator, that can determine total fuel requirements and weights for all vehicles in a particular trip.
models.py
from django.db import models
from django.db.models import Sum
# Create your models here.
class TripManager(models.Manager):
def get_vehicle_weight(self):
return self.get_queryset().all().aggregate(total_weight=Sum('vehicle__weight'))
def get_vehicle_fuel(self):
return self.get_queryset().all().aggregate(total_fuel=Sum('vehicle__fuel'))
class Vehicle(models.Model):
"""A vehicle may belong to multiple businesses and multiple trips at once."""
name = models.CharField(max_length=50, help_text="The common name of the vehicle.")
fuel_capacity = models.IntegerField(default=0, help_text="The total fuel capacity in gallons.")
burn_rate = models.FloatField(default=0, help_text="The burn rate of fuel in gal/h.")
weight = models.FloatField(default=0, help_text="The weight of the vehicle in pounds.")
def __str__(self):
return self.name
class Business(models.Model):
""""""
name = models.CharField(max_length=50, help_text="The name of the business.")
def __str__(self):
return self.name
class EmployeeType(models.Model):
"""Employee types can belong to many businesses."""
name = models.CharField(max_length=50, help_text="The title/role of a type of employee.")
def __str__(self):
return self.name
class Trip(models.Model):
"""A trip will be the primary object, composed of other objects that are associated with the trip."""
name = models.CharField(max_length=128)
vehicles = models.ManyToManyField(Vehicle, through="TripVehicle", through_fields=('trip', 'vehicle'),)
employee_types = models.ManyToManyField(EmployeeType, through="TripEmployeeType", through_fields=('trip', 'employee_types'),)
businesses = models.ManyToManyField(Business)
objects = TripManager()
class Meta:
base_manager_name = 'objects'
def __str__(self):
return self.name
class TripVehicle(models.Model):
trip = models.ForeignKey(Trip, on_delete=models.CASCADE)
business = models.ForeignKey(Business, on_delete=models.CASCADE)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
quantity = models.IntegerField()
class TripEmployeeType(models.Model):
trip = models.ForeignKey(Trip, on_delete=models.CASCADE)
business = models.ForeignKey(Business, on_delete=models.CASCADE)
employee_types = models.ForeignKey(EmployeeType, on_delete=models.CASCADE)
quantity = models.IntegerField()
views.py
def home(request):
trip = Trip.objects.all()
context = {
'trip' : trip,
}
return render(request, 'home.html', context=context)
The above 'home' page is just for my testing. I've pre-populated the DB with some basic vehicles, businesses, and employee types. However, when navigating to the 'home' url, I get the below error:
'QuerySet' object has no attribute 'get_vehicle_weight'
I am expecting to be able to create a 'trip' instance, then determine the sums of every vehicle attribute * the quantity of that type of vehicle for each trip. However, accessing the fields through 'trip.vehicles.get_vehicle_weight()' does not work.
What I expect to see:
# 3 cars with a weight of 1500 lbs each
trip.vehicles.get_vehicle_weight()
{'total_weight' : 4500}
What am I messing up with my implementation?

create fields according to a number in another field in django

I have 3 tables(Subjects, Sectors , Zones), one subject has many sectors and one sector has many zones
my auestion is how should i implent my models and views and serializers in sort of returning a json file indicating the name of the subject and the number of sectors and the number of zones in every sector. I tried this :
class Subject(models.Model):
name = models.CharField(max_length=200)
host = models.CharField(max_length=200,
primary_key=True)
nb_sectors = models.IntegerField(null=True)
def __str__(self):
return self.name
class Sector(models.Model):
name = models.CharField(max_length=200)
task = models.ForeignKey(Subject
,on_delete=models.CASCADE)
nb_zones = models.IntegerField(null=True)
def __str__(self):
return self.name
class Zone(models.Model):
name = models.CharField(max_length=200)
sector = models.ForeignKey(Sector
,on_delete=models.CASCADE)
status= ChoiceField(choices)
def __str__(self):
return self.name
You can define a ManyToManyField in the Subject table to the Sector table and in the Sector table to the Zone table. So your models.py will look like,
class Subject(models.Model):
name = models.CharField(max_length=200)
host = models.CharField(max_length=200,primary_key=True)
# other atribs...
sectors = models. ManyToManyField('Sector')
#property
def sectors_count(self):
return (self.sectors.count())
def __str__(self):
return self.name
class Sector(models.Model):
name = models.CharField(max_length=200)
# other atribs...
zones = models.ManyToManyField('Zone')
#property
def zones_count(self):
return (self.zones.count())
def __str__(self):
return self.name
class Zone(models.Model):
name = models.CharField(max_length=200)
status= ChoiceField(choices)
def __str__(self):
return self.name
In your subject serializer you can either specify a link to sector serializer
class SubjectSerializer(serializers.ModelSerializer):
sectors = SectorSerializer(read_only=True, many=True)
sectors_count = serializers.ReadOnlyField() # this is defined as property in the model
class Meta:
model = Subject
fields = '__all__'
class SectorSerializer(serializers.ModelSerializer):
zones_count = serializers.ReadOnlyField() # this is defined as property in the model
class Meta:
model = Sector
fields = '__all__'
Or you can also use a serializer method filed and iterate through all the zone object
class SubjectSerializer(serializers.ModelSerializer):
sectors = serializers.SerializerMethodField(required=False)
sectors_count = serializers.ReadOnlyField() # this is defined as property in the model
class Meta:
model = Subject
fields = '__all__'
def get_sectors(self, obj):
data = []
for sector in obj.sectors.all():
data.append({
'zones_count': sector.zones_count,
'name': sector.name
})
return data
If you want to re-use the sector serializer then you can go with the first one.

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

Many-to-one relationships ComboBox filtering

Experts!
Having the following models.py
class Country(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Meta:
verbose_name = 'Countries Uploaded'
class Users(models.Model):
name = models.CharField(max_length=50)
cUsers = models.ForeignKey(Country)
def __unicode__(self):
return self.name
class Meta:
verbose_name = 'Users on a country'
class GoalsinCountry(models.Model):
Country = models.ForeignKey(VideoTopic)
name = models.CharField(max_length=50)
descr = models.TextField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
verbose_name = 'Goals Topic'
I would like to filter out the users that belongs to a particular country and not all see all users when choosing a country on the combobox, and be able to save this information to a sqlite3 db.
if I add the following code below Country = Models..
gUser = models.ForeignKey(Users)
Using the Django admin interface, will show all users, not filtering users based on the country they are.. Would this be possible to do with Django + Something else? is there any working example/Tutorial - like the northwind MS Tutorial?
Thank you

django one to many issue at the admin panel

Greetings, I have these 2 models:
from django.db import models
class Office(models.Model):
name = models.CharField(max_length=30)
person = models.CharField(max_length=30)
phone = models.CharField(max_length=20)
fax = models.CharField(max_length=20)
address = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class Province(models.Model):
numberPlate = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
content = models.TextField()
office = models.ForeignKey(Office)
def __unicode__(self):
return self.name
I want to be able to select several Offices for Provinces, which is a one to many model. Here is my admin.py:
from harita.haritaapp.models import Province, Office
from django.contrib import admin
class ProvinceCreator(admin.ModelAdmin):
list_display = ['name', 'numberPlate','content','office']
class OfficeCreator(admin.ModelAdmin):
list_display = ['name','person','phone','fax','address']
admin.site.register(Province, ProvinceCreator)
admin.site.register(Office, OfficeCreator)
Right now, I am able to select one Office per Province at the admin panel while creating a new Province but I want to be able to select more than one. How can I achieve this?
Regards
I'm not sure if I'm misunderstanding you, but your models currently say "an office can be associated with many provinces, but each province may only have one office". This contradicts what you want. Use a ManyToMany field instead:
class Province(models.Model):
numberPlate = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
content = models.TextField()
office = models.ManyToManyField(Office)
def __unicode__(self):
return self.name

Categories

Resources