I am getting errors while I am building the following database. Idea is that you create a Team object. Create Student Objects and link them to Teams. And then give the Students points through PointEntry objects. I want to relate the team given to each Student object in each PointEntry Object. But for some reason, Django gives the error:
score_board.Student: (fields.E336) The model is used as an intermediate model by 'score_board.PointEntry.team', but it does not have a foreign key to 'PointEntry' or 'Team'.
Modeladmin Class
class StudentAdmin(admin.ModelAdmin):
list_display = ['name', 'team']
list_filter = ['team']
class PointEntryAdmin(admin.ModelAdmin):
list_display = ['student', 'points']
list_filter = ['student']
Below are the models
class Team(models.Model):
# Team/group model
name = models.CharField(max_length=64)
class Student(models.Model):
# Student model
name = models.CharField(max_length=64)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
def __str__(self):
return f"{self.name}"
class PointEntry(models.Model):
# Point entry's made by users appointed to a student in a group
student = models.OneToOneField(Student, on_delete=models.CASCADE)
points = models.IntegerField()
team = models.ManyToManyField(Team, through='Student')
Your through model needs a ForeignKey to both models. Since the model that defines the ManyToManyField is defined lower, you can not reference to the class. But in Django, you can also use a string literal:
class Student(models.Model):
name = models.CharField(max_length=64)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
pointentry = models.ForeignKey('PointEntry', on_delete=models.CASCADE)
def __str__(self):
return f'{self.name}'
class PointEntry(models.Model):
# Point entry's made by users appointed to a student in a group
student = models.OneToOneField(Student, on_delete=models.CASCADE)
points = models.IntegerField()
team = models.ManyToManyField(Team, through='Student')
Django will then replace the string with a reference to the class.
class Team(models.Model):
# Team/group model
name = models.CharField(max_length=64)
student = models. models.ManyToManyField(Student,through='PointEntry ')
class Student(models.Model):
# Student model
name = models.CharField(max_length=64)
team = models. models.ManyToManyField(Team,through='PointEntry')
def __str__(self):
return f"{self.name}"
class PointEntry(models.Model):
# Point entry's made by users appointed to a student in a group
student = models. ForeignKey(Student,on_delete=models.CASCADE)
team = models. ForeignKey(Team, on_delete=models.CASCADE)
points = models.IntegerField()
I think a model like this might work for what you’re trying to achieve.
Related
I am new to Django and I am trying to create a model for a website I am developing. So far I know how to implement everything I want to, but there is one thing that I cannot properly understand. So my idea is the following, in the models:
A class "Class" that can have as many "Teacher" and "Student" as wanted by the admin. I've been playing for a while with foreign key, but I can only manage to associate one student and teacher to a class, and whenever I want to display the "Class" info there is no Student or Teacher to display.
from django.db import models
from datetime import datetime
# Create your models here.
LANGUAGE_CHOICES = (
('english','ENGLISH'),
('spanish', 'SPANISH'),
('german','GERMAN'),
('french','FRENCH'),
('portuguese','PORTUGUESE'),
)
class Clase(models.Model):
name = models.CharField(max_length=300)
language = models.CharField(max_length=10, choices=LANGUAGE_CHOICES, default='english')
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=300)
clase = models.ForeignKey(Clase, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Teacher(models.Model):
name = models.CharField(max_length=300)
total_earnings = models.IntegerField()
month_earnings = models.IntegerField()
clase = models.ForeignKey(Clase, on_delete=models.CASCADE)
def __str__(self):
return self.name
Since a Clase can have 'as many "Teacher" and "Student" as wanted' it may make sense to define the relationships with ManyToManyFields. I assume a Teacher and a Student can have more than 1 Clase?
class Clase(models.Model):
name = models.CharField(max_length=300)
language = models.CharField(max_length=10, choices=LANGUAGE_CHOICES, default='english')
students = models.ManyToManyField(Student)
teachers = models.ManyToManyField(Teacher)
def __str__(self):
return self.name
Then you can remove the foreign keys on the Student and Teacher models. Now when you edit a Clase in the admin you should be able to add as many students and teachers as you want
Does the 'through' argument in ManyToManyField in Django includes all fields in the related tables? For example will Group contain all Person and Membership fileds? And also how many levels deep can 'through' relationships can be?
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Yes when you use a through field the associated models' fields are all accessible from the related table. Levels can be deep as you can but it gets complicated better just to create separate tables.
I am trying to create the proper Django model that could fit the following reqs:
Person Class has 1 to many relations with the Address Class
Person Class has many to many relations with the Group Class
Book Class contains the collections of the Persons and the Groups
This is my code:
class Person(models.Model):
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=20)
def __str__(self):
return self.first_name+ ' - ' + self.last_name
class Address(models.Model):
person = models.ForeignKey(Person)
address_line = models.CharField(max_length=200)
def __str__(self):
return self.address_line
class Group(models.Model):
group_name = models.CharField(max_length=12)
persons = models.ManyToManyField(Person)
def __str__(self):
return self.group_name
class Book(models.Model):
record_name = models.CharField(max_length=12)
person = models.ForeignKey(Person )
group = models.ForeignKey(Group )
def __str__(self):
return self.record_name
However it's not correct:
1) A Group can now contain multiple Persons but the Persons do not contain any Group.
I am not sure if I should add to the Person class the following code:
groups = models.ManyToManyField(Group)
2) The Book class now contains only 1 record of Person & Group per Book record.
3) When I added the Foreign Keys to the models, I removed
on_delete tag:
person = models.ForeignKey(Person, on_delete=models.CASCADE())
because it does not compile it, asking for some params.
I know how to make all this for C#, but I am a kinda stucked with this simple task in Python/Django.
1) The ManyToMany field should appear only in one of the models, and by looks of things you probably want it in the Person model.
Its important to understand that the data about the ManyToMany field is saved in a differant table. Django only allows this field to be visable through buth models (so basiclly, choose where it is move convinient).
2)By the look of your structure I will suggest you use a ManyToMany field through a different table. here is an example:
class Activity(models.Model):
name = models.CharField(max_length=140)
description = models.TextField(blank=True, null=True)
class Route(models.Model):
title = models.CharField(max_length=140)
description = models.TextField()
activities_meta = models.ManyToManyField(Activity, through = 'RouteOrdering')
class RouteOrdering(models.Model):
route = models.ForeignKey(Route, on_delete=models.CASCADE)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='activita')
day = models.IntegerField()
order = models.IntegerField(default=0)
that way the data is binded to the ManyToMany field
How to implement a list in a Django model?
Lets say I have a UserProfile model, and each user can have a list of mortgages (undefined quantity) defined by MortgageModel.
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# list of morgtages?
my only idea is to make a old school list, where every mortgage can point to another one or null, like this:
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
next_mortgage = MortgageModel(null=True, default=null)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
mortgages = MortgageModel(null=True, default=null)
is there any other possibility?
You'll have to assign a ForeignKey to User , so that each Mortgate 'belongs' to a user.
That is how a One-To-Many relationship is done. Then, if you want to get the list of Mortgages a user have, you'd filter them out like MortgageModel.objects.filter(related_user=user)
So, you'd have something like
Model
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
related_user = models.ForeignKey(UserProfile)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
View
list_of_mortages = MortgageModel.objects.filter(related_user=user)
My model's ER diagram in here
This is part of my models.py.
class Company(models.Model):
user = models.OneToOneField(User)
company_id = models.AutoField(primary_key=True)
...
class Store(models.Model):
store_id = models.AutoField(primary_key=True)
store_company = models.ForeignKey('Company', related_name='storecompany')
store_city = models.ForeignKey('City', related_name='cities', to_field='city_name')
...
class Discount(models.Model):
discount_id = models.AutoField(primary_key=True)
discount_category = models.ManyToManyField(Category, related_name="discountcategory")
discount_store = models.ManyToManyField(Store, related_name="discountstores")
...
class City(models.Model):
city_name = models.CharField(primary_key=True, max_length=25)
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
category_name = models.CharField(max_length=50)
I want to filter discounts with their city. All discounts have a city. For example I received some city name, "bursa" in "city" variable. And I want to filter all discounts in "bursa" city. Maybe my model isn't right but I don't know.
I tried a lot of filter but I couldn't.
First, in your class Store, the related_name is not "correct", it should be something like "stores" not "cities" because related_name attribute specifies the name of the reverse relation from the City model back to your model.
Less assume that you changed it.
class Store(models.Model):
store_id = models.AutoField(primary_key=True)
store_company = models.ForeignKey('Company', related_name='storecompany')
store_city = models.ForeignKey('City', related_name='stores', to_field='city_name')
Then, given a city name
your_city = City.objects.filter(city_name='city_name')[0]
stores = your_city.stores.all()
discounts = [store.discountstores.all() for store in stores]
Always start from the model you actually want to get. If you want Discounts, query that model, using the double underscore syntax to traverse relationships.
Discount.objects.filter(discount_store__store_city__city_name="bursa")