I am struggling to understand how one-to-many and many-to-many relation works in Django model. My schema looks something like this so far, I am open for suggestions to make it better.
A many-to-many relation between users and team. Also, there will be schedules that belong to a particular user of a team.
This is how my model looks like so far,
class Team(models.Model):
tid = models.AutoField(primary_key=True)
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
class Schedule(models.Model):
sid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
class BelongsTo(models.Model):
bid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE)
Question: I want to get the information of each user, what are their schedules and which team each schedule belongs to. How would I to do it? I have tried BelongsTo.objects.select_related().all(), but it is not working for me.
Note: I am open for suggestions, if something is wrong with my schema or model or the approach, please let me know.
BelongsTo is seems like utility table.So
BelongsTo.objects.all().values('user', 'team__team_name', 'schedule')
Your schema looks almost right, but I would modify it a little bit. In particular, I will change how Schedule is implemented. Instead of having a sid in the User Belongs To join-table, I would include the user and team in the Schedule table as foreign keys.
This is how the Django models should then look like:
class User(models.Model):
username = models.CharField(max_length = 200)
# put other fields like password etc. here
class Team(models.Model):
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
user = models.ManyToManyField("User")
class Schedule(models.Model):
user = models.ForeignKey("User")
team = models.ForeignKey("Team")
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
Note the following:
You don't need to have a primary key field in the models because Django adds a primary key field called pk or id automatically.
Note the absence of the User Belongs To model. Django implements join-tables like User Belongs To automatically when you use a ManyToManyField. See the Django docs on many-to-many relationships.
You also don't need on_delete = models.CASCADE on ForeignKey fields, because this is the default behavior.
To see how to get information about users, teams and schedule from this configuration of models, consult the Django documentation on making db queries. It's quite easy.
Related
I am making a blog website and I am facing some issues with the Query performance.
I have 3 models
User Model -> Users (To store user email, Password etc)
Post Model -> Actual Posts
people Model -> (To store users extra information)
Post Model ->
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
title = models.CharField(max_length=255,null=True)
description = models.CharField(max_length=1000,null=True)
Likes = models.ManyToManyField(to=User, related_name='Post_likes')
favourites = models.ManyToManyField(to=User,blank=True,related_name="favourite")
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
Now as both of these models are connected to User model. I want to query the Post model and get the user photo in the template. Now when I use post.user.people.photo then for every post it generates a seperate query to DB resulting in slowness. I would like to use Join here to combines multiple tables and fetch all the records at once.
I am currently using following Query ->
posts = Post.objects.select_related().prefetch_related('images_set').annotate(comments_Count = Count('comments_post',distinct=True)).annotate(Count('Likes',distinct=True)).all().order_by('-id')
You can perform a .select_related(…) [Django-doc] on the user and the people with user__people, so:
posts = Post.objects.select_related(
'user__people', 'category'
).prefetch_related('images_set').annotate(
comments_Count = Count('comments_post',distinct=True),
Count('Likes',distinct=True)
).order_by('-id')
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I'm doing some querying currently and I was wondering if I would be able to query something from these 3 models where the return would give me all the projects the users are working on. I know about the basic filtering however thats not really enough in this case, how would one go about querying through 2 foreign keys.
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
class ProjectUser(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE)
user = models.ForeignKey("User", on_delete=models.CASCADE)
is_lead = models.BooleanField(default=False)
class Meta:
unique_together = (("project", "user"),)
class Project(models.Model):
name = models.CharField(max_length=255)
client = models.CharField(max_length=255)
complete = models.BooleanField(default=False)
You can obtain the Projects a user is working on with:
Project.objects.filter(
projectuser__user=user
)
The double underscores are used to look "through" relations. Furthermore the default related_query_name=… parameter [Django-doc] is, if not specified, the name of the model in lowercase.
I have Django Models Says,
class JobApplication(models.Model):
job_application_id = models.AutoField(primary_key=True)
user_id = models.ForeignKey(User)
resume_id = models.ForeignKey(Resume)
class Resume(models.Model):
resume_id = models.AutoField(primary_key=True)
resume_name = models.CharField()
.... other fields
class Education(models.Model):
education_id = models.AutoField(primary_key=True)
resume_id = models.ForeignKey(Resume)
degree_name = models.CharField()
.... other fields
class Experience(models.Model):
experience_id = models.AutoField(primary_key=True)
resume_id = models.ForeignKey(Resume)
company_name = models.CharField()
.... other fields
class Skills(models.Model):
skill_id = models.AutoField(primary_key=True)
resume_id = models.ForeignKey(Resume)
skill_name = models.CharField()
.... other fields
I want to a query-set that against a given job_id in jobapplication model, it should fetch all its related education, experience, skills etc with reference to resume id against job id.
For Now, I do this in Single quires, like i fetch resume_id from job_application then fetch resume details with reference
resume_against_job =Jobapplication.objects.get_query_set().get_complete_Jobapplication(job_id)
for resum in resume_against_job:
resume_dict = {}
resume_id = resum['resume_id']
user_id = resum['user_id']
then against these user_id and resume_id, i wrote another queries to fetch user details and their resume detail.
To answer your question, you can only do separate queries on each model if you have the resume_id (I see it on each model you have), maybe you can wrap them in one function, but it doesn't get any simpler than that.
I think your fundamental problem is in the database design. If you have resume_id in each model, why not merge all of them into Resume model? Sounds like they all belong to that model, if each Education, Experience, Skill is Resume specific. You only create separate model if resumes share common Education, Experience or Skill, but then they should be foreign keys on the Resume model. Also in this case, you only query on Resume model and get all other information instead of searching on multiple places.
Looking for advice on setting up this model.
This job board app has Company, Location, and Job. They should have the following relationships:
A Company can have multiple locations
A Company can have multiple jobs
A Job can have only one Company
A Job can have multiple locations, BUT each Location must be valid for the job's Company
I'd like to create a model that reflects these relationships. I think something like this might work:
class Company(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
class Location(models.Model):
is_primary_location = models.BooleanField()
address = models.CharField(max_length=200)
company = models.ForeignKey(Company)
class Job(models.Model):
title = models.CharField(max_length=200)
company = models.ForeignKey(Company)
location = models.ForeignKey(Location)
But I would really like the "Job has Location(s) through Company" relationship to be enforced. The model doesn't enforce it; I think I'd have to filter the valid Locations when data is displayed, and I'd like to avoid that.
Thanks very much!
Take a look at ForeignKey.limit_choices_to.
This allows you to filter the available choices and is enforced in ModelForm. Since you already have the company foreign key in your Job model, you should be able to use that to filter the choices.
I ended up using https://github.com/digi604/django-smart-selects and wrote the model like this. I don't think limit_choices_to works in this case (according to other SO threads)
from smart_selects.db_fields import ChainedForeignKey
class Company(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
class Location(models.Model):
is_primary_location = models.BooleanField()
address = models.CharField(max_length=200)
company = models.ForeignKey(Company)
class Job(models.Model):
title = models.CharField(max_length=200)
company = models.ForeignKey(Company)
location = ChainedForeignKey(
Location,
chained_field="company",
chained_model_field="company",
show_all=False,
auto_choose=True
)
I have two MySQL models:
class registration(models.Model):
name = models.CharField(max_length=30)
email = models.EmailField()
password = models.CharField(max_length=30)
company = models.CharField(max_length=30)
class personal_details(models.Model):
reg = models.ForeignKey(registration)
job = models.CharField(max_length=30)
experience = models.IntegerField(default=0)
I want to filtering details using both experience and company as a keyword. I want to fetch and display details(name, email, company, job, experience) from both tables in my HTML page.
You can do it inside the filter() so you should do something like this
I'm working from the personal_details object now:
filteredResults = personal_details.objects.filter(experience="grasscutting", reg__company="IBM")
This will give you a list of objects found.
The magic here is that you can access ForeignKey relationships with the __ convention.