Django Querysets | Backward, Reverse and ManyToMany Relationships

Table Of Contents

Select Objects Using Backward/Reverse Relationships

Below query is an example of a reverse relationship where we have Course objects which have ForeignKey relationship with Subject Model.
If you have already gone through our post on Django Quersets | One To One Foreign Key, Inner Joins, Query Filtering then you have learnt to retrive course subjects from Subject Model.

>>> bca_course = Course.objects.get(pk=1)
>>> print(bca_course)
BCA
>>> #Now we will get All Subjects of BCA Course Through Backward Relationship
>>> bca_subjects = bca_course.subject_course.all()
>>> print(bca_subjects)
<QuerySet [<Subject: C Programming>, <Subject: DataStructures using C>, <Subject: Visual Programming>]>

bca_course.subject_course returns all the subjects related to a course.This is a great advantage over other frameworks where you have to manually specify reverse/backward relationships.

>>> bba_course = Course.objects.get(pk=3)
>>> print(bba_course)
BBA
>>> bba_subjects=bba_course.subject_course.all()
>>> print(bba_subjects)
<QuerySet [<Subject: Business Administration>, <Subject: Economics>, <Subject: Accounting>, <Subject: Introduction to Taxation>, <Subject: Business Marketing>]>

Get Student List of who is enrolled to a specific Course through Backward Relationship

>>> bca_course = Course.objects.get(pk=1)
>>> print(bca_course)
BCA
>>> student_list = bca_course.course.all()
>>> print(student_list)
<QuerySet [<Student: Suresh>, <Student: Kiran>, <Student: Vasudev>]>

The bca_course.course gets a list of students from Student Model who enrolled to course BCA.

Accessing other model information through student object.

>>># Access field values by index
>>> student_list[1]
<Student: Kiran>
>>> student_list[1].name
'Kiran'
>>> student_list[1].joining_date
datetime.date(2018, 2, 5)
>>> student_list[1].course.course_name
'BCA'
>>> student_list[1].course.id
1
>>> student_list[1].course.course_desc
'BCA fullform (Bachelor of Computer Application) is a 3 year course which provides basic knowledge of computer programming and application'

Get list all student enrolled to any course using Backward Relationship

>>>course_list = Course.objects.all()
>>>student_list = []
>>>for course in course_list:
        [student_list.append(student) for student in course.course.filter()]    
>>> print(student_list)
[<Student: Suresh>, <Student: Kiran>, <Student: Vasudev>, <Student: Rakshit>, <Student: Amar>, <Student: Prakash>, <Student: Naresh>]

Here we get all courses and loop over and get student belonging to that particular course.

ManyToMany Relationship

Let us create another model ExamMarks which has a ManyToMany relationship with Student and Subject Model.
In models.py.

class ExamMarks(models.Model):  
    id = models.AutoField(primary_key=True)
    student = models.ManyToManyField(Student,related_name="exam_marks_student")
    subject=models.ManyToManyField(Subject,related_name="exam_marks_subject")
    obtained_marks = models.FloatField(max_length=12)

    class Meta:
        db_table="subject_marks"
        verbose_name="Subject Marks"
    
    def __str__(self):
        return str(self.obtained_marks)

After migrating this model we get 3 tables in MySQL they are subject_marks which has id and obtained_marks field.
subject_marks_student table which has id,exammarks_id and student_id as ForeignKey.
subject_marks_subject table which has id, exammarks_id and subject_id as ForeignKey.

Populating ExamMarks Models

Adding marks scored by students. We will intentionally exclude a few students as they did not attend the exam.

>>> from query_sets.models import Course, Subject, Student, ExamMarks
>>> 
>>> bba_course = Course.objects.get(pk=1)
>>> bca_course = Course.objects.get(pk=3)
>>> 
>>> bba_ecomonics = Subject.objects.get(pk=5)
>>> student_1 = Student.objects.get(pk=2)
>>> 
>>> exam_marks_1 = ExamMarks(obtained_marks=74.5)
>>> exam_marks_1.save()
>>> 
>>> exam_marks_1.student.add(student_1)
>>> exam_marks_1.save()
>>> exam_marks_1.subject.add(bba_ecomonics)
>>> exam_marks_1.save()
>>> 

>>> bba_business_marketing = Subject.objects.get(pk=8)
>>> exam_marks_2 = ExamMarks(obtained_marks=55)
>>> exam_marks_2.student.add(student_1)
>>> exam_marks_2 = ExamMarks(obtained_marks=55)
>>> exam_marks_2.save()
>>> exam_marks_2.student.add(student_1)
>>> exam_marks_2.save()
>>> exam_marks_2.subject.add(bba_business_marketing)
>>> exam_marks_2.save()

>>> bca_visual_prog = Subject.objects.get(pk=3)
>>> student_2=Student.objects.get(pk=5)
>>> exam_marks_3=ExamMarks(obtained_marks=65.00)
>>> exam_marks_3.save()
>>> exam_marks_3.student.add(student_2)
>>> exam_marks_3.save()
>>> exam_marks_3.subject.add(bca_visual_prog)
>>> exam_marks_3.save()
>>> 
>>> bba_taxation = Subject.objects.get(pk=7)
>>> student_3=Student.objects.get(pk=1)
>>> exam_marks_4=ExamMarks(obtained_marks=59.5)
>>> exam_marks_4.save()
>>> exam_marks_4.student.add(student_3)
>>> exam_marks_4.subject.add(bba_taxation)
>>> exam_marks_4.save()

Filtering Querysets from ManyToMany

Get Marks Secured by a student and other student details

>>> from query_sets.models import Course, Subject, Student, ExamMarks
>>> student = Student.objects.get(pk=5)
>>> print(student)
Vasudev
>>> subject_attended_on_exam = ExamMarks.objects.filter(student=student)
>>> print(subject_attended_on_exam)
<QuerySet [<ExamMarks: 65.0>]>
>>> #Get Student other details
>>> student_object = subject_attended_on_exam[0].student.get()
>>> print(student_object)
Vasudev
>>> print(student_object.course.course_name)
BCA
>>> print(student_object.course.subject_course.filter())
<QuerySet [<Subject: C Programming>, <Subject: DataStructures using C>, <Subject: Visual Programming>]>

First, we select a student object from the model Student and filter in ExamMarks model this gets use list of matched objects.
Through subject_attended_on_exam objects we can get student information as well by subject_attended_on_exam[0].student.get().

Get a list of subjects with marks by student course

>>>from query_sets.models import Course, Subject, Student, ExamMarks
>>>student_list = Student.objects.all()
>>>for student in student_list:
student.subjects = student.course.subject_course.filter()
for subject in student.subjects:
    try:
        subject.marks_scored = ExamMarks.objects.get(student=student,subject=subject)
    except:
        subject.marks_scored=[]

>>> print(student_list)
<QuerySet [<Student: Rakshit>, <Student: Amar>, <Student: Suresh>, <Student: Kiran>, <Student: Vasudev>, <Student: Prakash>, <Student: Naresh>]>
>>>print(student_list[1].subjects[1])
Economics
>>>print(student_list[1].subjects[1].marks_scored.obtained_marks)
74.5
>>> print(student_list[1].subjects[3])
Introduction to Taxation
>>> print(student_list[1].subjects[3].marks_scored)
[]

In this query, you’ll be retrieving the list of all student object with their marks by a particular subject.

Note

You can find complete documentation regarding Django querysets

Conclusion

In conclusion, you have come to an end of this post on Django Quersets | Backward, Reverse and Many To Many Relationships.
Comment below for more suggestions.

Summary
Review Date
Reviewed Item
Django Quersets | Backward, Reverse and Many To Many Relationships
Author Rating
51star
1star1star1star1star
Software Name
Django Web Framework
Software Name
Windows Os, Mac Os, Ubuntu Os
Software Category
Web Development