Making queries that involves ForeignKey in Django - django

Apologies on the last question. Should have phrased it better.
I have three classes, Student and another Adult and AdultProfile. I would like to make a query such that it gets all the adults who are from US but it has to be done using Student class. This is because my queryset is Student.objects.all() and based on this queryset, i would like to get all the adults(through AdultProfile) from US . This is an example of the code while the original code much more complex and longer. This example shows the gist of the problem.
class Student(models.Model):
name = models.CharField(max_length=255)
birthday= models.DateField(blank=True,null=True)
class Adult(models.Model):
user = models.OneToOneField(User)
parent= models.ForeignKey(Student,related_name="relationships")
class AdultProfile(models.Model):
country = models.CharField(max_length=2)
adult = models.OneToOneField(Adult,related_name='profile')
Need some help in this.. Hope i have phrased it better this time...

You're not going to be able to do this from a Student queryset. The only way you will end up with Adult objects from a Student class is from a Student instance via its reverse-related-accessor: student_instance.relationships.all().
The missing ingredient in your django ORM travels is probably the fact that you can query related objects (FK, OneToOne) via its related_name (or by default, the model name).
student_qs = Student.objects.all() # some query
adults_in_us = Adult.objects.filter(parent__in=student_qs, profile__country='US')

Related

How to expand application to work with multiple users and seasons

Let's say that I have created an app for a school with several models (e.g. Student, Teacher, Course, Attendance, Grade, Timetable, Payments etc).
It's working great for the current year. But now I want to expand my application, so that several schools can use it and it can store data of (mostly) independent seasons/years.
The first solution that comes to my mind, is to add 2 extra models (1)school=user and (2)season=year. And then add ForeignKeys from (almost) ALL my models to both of these (school, season).
(Maybe I could add a third model named SchoolSeason, with just these 2 fields and use this as FK to all my fields.)
Is there a more elegant solution?
Edit: a drawback to this solution would be that the models (e.g. Students) will share their auto-incremented ID with other schools.
Hard to tell without your current models but I would to the same by adding to 2 extra models. But no need to add both of them to all of your models : only Season is needed if you link Season to School.
class School(models.Model):
name = models.CharField(...)
class Season(models.Model):
school = models.ForeignKey(School)
name = models.CharField(...)
other_fields...
Each Season is linked to a School. Then, you can add the Foreign Key to all of your models.
About your problem in the edit, you are right, it would be a problem. You should not use auto-incremented key but UUid.
Finally, it would look like :
class BaseSeasonModel(models.Model):
uid = models.UUIDField(
primary_key=True,
default=uuid_lib.uuid4,
editable=False,
)
season = models.ForeignKey(Season)
class Meta:
abstract = True
And all of your models would inherit from it :
class Student(BaseSeasonModel):
...

How to call a a field of one model A into another model B so that b can work as a view

I have created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.

Database normalization in django

I need an optimally normalized database structure to achieve the following requirement.
models.py
class Learning_Institute(models.Model):
name = models.TextField()
user = models.ManyToManyField(settings.AUTH_USER_MODEL)
class Course(models.Model):
title = models.CharField(max_length=50)
instructor = models.ForeignKey(User, on_delete=models.PROTECT, related_name='courses_taught')
institute = models.ForeignKey(Learning_Institute, on_delete=models.PROTECT, related_name='courses')
I need the instructor field in the Course table to be limited to the set of users in Learning_Institute instead of all the users in the system.
How do I achieve this on the DB level?
I don't think that you can limit in the model itself.
One of the things that you can do is on form save to have validations using form clearing methods like so
And you can create a check that does something like this:
def clean_ instructor(self):
instructor = self.cleaned_data['instructor']
if instructor.type != "instructor":
raise forms.ValidationError("The user is not instructor!")
Another option is to create another User object that will inherit User and you can call it InstrcutorUsers
I have used this tutorial to extend the user model in django
I don't know if it's suitable for your scenario but changing the relations slightly may achieve what you want.
Removing the many to many for User and create a concrete association model for it, will
at least make sure the Course can only have users that also are instructors, by design.
Consider the following model structure:
class LearningInstitute(models.Model):
name = models.TextField()
class InstituteInstructor(models.Model):
class Meta:
unique_together=('user','institute')
user = models.ForeignKey(User, on_delete=models.PROTECT)
institute = models.ForeighKey(LearningInstitute, on_delete=models.PROTECT)
class Course(models.Model):
title = models.CharField(max_length=50)
instructor = models.ForeignKey(InstituteInstructor, on_delete=models.PROTECT)
You have LearningInstitutes
A user can be an instructor with a related institute, a User can only be related to the same institute once
A Course can only have an instructor (and by that also the related institute)
Design can easily be extended to let Courses have multiple instructors.
By design the Course can only have users that are also instructors.
There is a possibility in Django to achieve this in your model class. The option that can be used in models.ForeignKey is called limit_choices_to.
First I'd very strongly recommend to rename the field user in the class LearningInstitute to users. It is a many to many relation, which means an institute can have many users, and a user can perform some work in many institutes.
Naming it correctly in plural helps to better understand the business logic.
Then you can adapt the field instructor in the class Course:
instructor = models.ForeignKey(
'User', # or maybe settings.AUTH_USER_MODEL
on_delete=models.PROTECT,
related_name='courses_taught',
limit_choices_to=~models.Q(learning_institute_set=None)
)
This is not tested and probably will need some adjustment. The idea is to get all User objects, where the field learning_institute_set (default related name, since you haven't specified one) is not (the ~ sign negates the query) None.
This has however nothing to do with normalisation on the database level. The implementation is solely in the application code, and the database has no information about that.
As suggested by #TreantBG, a good approach would be to extend the class User and create class Instructor (or similar). This approach would affect the database by creating an appropriate table for Instructor.

Django - How to build an intermediate m2m model that fits? / best practice

First of all I have to admit that I'm quite new to all this coding stuff but as I couldn't find a proper solution doing it myself and learning to code is probably the best way.
Anyway, I'm trying to build an app to show different titleholders, championships and stuff like that. After reading the Django documentation I figured out I have to use intermediate models as a better way. My old models.py looks like this:
class Person(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
[...]
class Team(models.Model):
name = models.CharField(max_length=64)
team_member_one = models.ForeignKey(Person)
team_member_two = models.ForeignKey(Person)
class Championship(models.Model):
name = models.CharField(max_length=128)
status = models.BooleanField(default=True)
class Titleholder(models.Model):
championship = models.ForeignKey(Championship)
date_won = models.DateField(null=True,blank=True)
date_lost = models.DateField(null=True,blank=True)
titleholder_one = models.ForeignKey(Person,related_name='titleholder_one',null=True,blank=True)
titleholder_two = models.ForeignKey(Person,related_name='titleholder_two',null=True,blank=True)
Championships can be won by either individuals or teams, depending if it's a singles or team championship, that's why I had to foreign keys in the Titleholder class. Looking at the Django documentation this just seems false. On the other hand, for me as a beginner, the intermediate model in the example just doesn't seem to fit my model in any way.
Long story short: can anyone point me in the right direction on how to build the model the right way? Note: this is merely a question on how to build the models and displaying it in the Django admin, I don't even talk about building the templates as of now.
Help would be greatly appreciated! Thanks in advance guys.
So I will take it up from scratch. You seem to be somewhat new to E-R Database Modelling. If I was trying to do what you do, I would create my models the following way.
Firstly, Team would've been my "corner" model (I use this term to mean models that do not have any FK fields), and then Person model would come into play as follows.
class Team(models.Model):
name = models.CharField(max_length=64)
class Person(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
team = models.ForeignKey(to=Team, null=True, blank=True, related_name='members')
This effectively makes the models scalable, and even if you are never going to have more than two people in a team, this is good practice.
Next comes the Championship model. I would connect this model directly with the Person model as a many-to-many relationship with a 'through' model as follows.
class Championship(models.Model):
name = models.CharField(max_length=64)
status = models.BooleanField(default=False) # This is not a great name for a field. I think should be more meaningful.
winners = models.ManyToManyField(to=Person, related_name='championships', through='Title')
class Title(models.Model):
championship = models.ForeignKey(to=Championship, related_name='titles')
winner = models.ForeignKey(to=Person, related_name='titles')
date = models.DateField(null=True, blank=True)
This is just the way I would've done it, based on what I understood. I am sure I did not understand everything that you're trying to do. As my understanding changes, I might modify these models to suit my need.
Another approach that can be taken is by using a GenericForeignKey field to create a field that could be a FK to either the Team model or the Person model. Or another thing that can be changed could be you adding another model to hold details of each time a championship has been held. There are many ways to go about it, and no one correct way.
Let me know if you have any questions, or anything I haven't dealt with. I will try and modify the answer as per the need.

Weak Entities in Django

Can somebody please explain me how to represent a weak entity relationship in django?
i searched for it in django's documentation, but couldn't find. I even searched on google and stackoverflow before posting a question here.
In case its not possible to represent a weak entity relationship, then please let me know what is the most appropriate alternative to it in django
Update:
I was developing an e-learning site, so there's a Course class with attributes like title, description, creator, etc. and I want to add a weak entity called "Week" (to store week-wise content for the course) which would be attached to this strong entity called Course, and I wanted course_id from Course class and week_no from Week class to act as a primary key for each entry in Week class
Well, let's take this example from wikipedia
You have a class Order and a class Product.
You'd then have a class OrderItem which would be the weak entity.
class Order(models.Model):
some_attributes
class Product(models.Model):
some_other_attributes
class OrderItem(models.Model)
order = models.ForeignKey(Order)
product = models.ForeignKey(Product)
other_attributes
class Meta:
unique_together = (order, product)
the unique_together meta property would make sure each OrderItem's won't have more than a database entry where both these values are repeated.
I reckon this may not match exactly what it you're looking for, but it may be a start. If you provide more details on what's you're trying to accomplish, perhabs I can help with some table tweaking or even query examples for getting data using this approach.
edit:
You are correct, there is no such field as weaker entity field. My sugestion is that you treat the week model as you would any other. And link it to the Course model, like so:
class Course(models.Model):
title = models.CharField()
description = models.CharField()
etc..
class CourseWeek(models.Model):
course = models.ForeignKey(Course)
week_number = models.IntegerField()
topic = models.CharField()
slideshow = models.FileField()
class Meta:
unique_together = ('course' , 'week_number')
Hope this helps :)