Django Querysets | One To One Foreign Key, Inner Joins, Query Filtering

Django provides a data abstraction layer between models and database tables. Querysets are used to retrieve data from tables and other save, update and delete operations.
There is various queryset function provided by Django to satisfy needs. Querysets are python objects which include information about that particular Course.objects.create.

In this post, we’ll be discussing the basics of Querysets

Table of Contents

By taking an example of students, courses and subjects are tables. First, we’ll create models and migrate to database.
In our app named query_set has models.py file. if doesn’t exist then create one.

from django.db import models

class Course(models.Model):
    id=models.AutoField(primary_key=True)
    course_name=models.CharField(max_length=200)
    course_desc=models.TextField(null=True)
    created_at=models.DateTimeField(auto_now_add=True)
    updated_at=models.DateTimeField(auto_now=True)

    class Meta:
        db_table="courses"
        verbose_name_plural="Courses"

    def __str__(self):
        return self.course_name

class Subject(models.Model):
    id=models.AutoField(primary_key=True)
    course=models.ForeignKey(Course,related_name="subject_course",on_delete=models.CASCADE)
    subject_name=models.CharField(max_length=200)
    created_at=models.DateTimeField(auto_now_add=True)
    updated_at=models.DateTimeField(auto_now=True)

    class Meta:
        db_table="subjects"
        verbose_name_plural="Subjects"

    def __str__(self):
        return self.subject_name

class Student(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=200)
    course=models.ForeignKey(Course,related_name="course",on_delete=models.CASCADE)
    joining_date=models.DateField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table="students"
        verbose_name_plural="Students"

    def __str__(self):
        return self.name

Course model is an independent model which has course_name as the mandatory field next, we have Subject the model which has a ForeignKey relationship with Course model
as a particular course may have multiple subjects and Student model has name,course and joining_date as mandatory fields and has ForeignKey relationship with Course model
as many students may take up some courses. We’ll not be going in a detailed explanation of creating models and model fields in this topic we’ll be focussing on make queries.

Creating a new Object

Let us include models in our python shell. Go to root project and type python manage.py shell in terminal.

>>> from query_sets.models import Course, Subject, Student
>>> course = Course.objects.create(course_name="BCA",course_desc="Bachelor of Computer Application")
>>> print(course)
BCA

Path to models can be given through from .models import ,. We have called Course.objects.create() method where Course in model and objects is a Default Manager for model Course.
For every model, there is at least one manager by default. Finally `create()` method within `objects` manager which creates a new row in courses table and returns that object.
When we print(course) displays name format as specified in __str__(self) a method in Course model.

Accessing Objects

Querysets has methods of accessing objects from the table and they are get() and filter() method.

  • get() – The method returns a single object useful in getting a particular object by primary key.
  • filter() – The method returns list-objects useful which retrieve by a set of conditions.

Here we’ll be using get() to retrieve already saved BCA course.

>>>from query_sets.models import Course, Subject, Student
>>>course = Course.objects.get(id=1)
>>>print(course)
BCA
>>>print(course.course_desc)
Bachelor of Computer Application

Using dot( . ) operator we can access fields of Course Model. The get() the method takes keyword argument here the keyword argument is id equals to.
Insisted explicitly specifying id we can specify pk which means as primary_key of that particular model Course.objects.get(pk=1) which also returns the course object.

Accessing object by filter() method.

>>> from query_sets.models import Course, Subject, Student
>>> course = Course.objects.filter(pk=1)
>>> print(course)
<QuerySet [<Course: BCA>]>

The filter() methods return list objects which has a single object. This method is useful in retrieving a list of data and returns empty QuerySet list if filter conditions are not matched.
Whereas get() method if object by id not found then an exception is raised query_sets.models.DoesNotExist: Course matching query does not exist.

>>> course = Course.objects.filter(pk=10)
>>> print(course)
<QuerySet []>
>>> course = Course.objects.get(pk=10)
Traceback (most recent call last):
query_sets.models.DoesNotExist: Course matching query does not exist.

Updating Objects

Updating objects is easier simply call .save() on the object, if the primary key exists then object get updated else if the primary key is None the new object is created.
Let us try to update course_desc of Course model.

from query_sets.models import Course, Subject, Student       
>>> course = Course.objects.get(pk=1)
>>> print(course.course_desc)
Bachelor of Computer Application
>>> course.course_desc = "BCA fullform (Bachelor of Computer Application) is a 3 year course which provides basic knowledge of computer programming and application"
>>> course.save() #this updates the database

Deleting Objects

>>> course = Course.objects.get(pk=1)
>>> print(course)
BCA
>>> course.delete()
(1, {'query_sets.Subject': 0, 'query_sets.Course': 1, 'query_sets.Student': 0})

Each QuerySet object carries .delete() method and when called the object get deleted from the database. course.delete() returns a tuple which has information related mapped records being deleted.

OneToOne and ForeignKey relationships between models

OneToOne Relationship

This relationship can be set in the model. We need to specify other model names which will be mapped to this model. By default, unique=True is enabled which means that there must be only one unique field of that particular column in the table. If a duplicate is detected than exception django.db.utils.IntegrityError: (1062, “Duplicate entry”) is raised.

ManyToMany Relationship

This relationship is shared a lot of similarities with OneToOne Relationship but the only difference is it doesn’t have unique attribute set to True.

Query Filter and Mapping Objects

Now let us insert subjects for our course BCA.

>>> course = Course.objects.get(pk=1)
>>> subject_1=Subject.objects.create(course=course,subject_name="C Programming")
>>> subject_2=Subject.objects.create(course=course,subject_name="DataStructures using C")
>>> subject_3=Subject.objects.create(course=course,subject_name="Visual Programming")

First, we’ll get single course object from Course Model and while creating subjects insisted of passing course_id to create method we can directly pass course object and Django it will map newly created subject to that course.

Django model API provides more features other than retrieving and creating objects. In Subject the model we have specified field course as a ForeignKey relationship with Course Model.
In other frameworks, we must explicitly declare relationships in the model. But Django will get course details from subject-object.
Now access the course through subject

from query_sets.models import Course, Subject, Student
>>> subject_1=Subject.objects.get(pk=1)
>>> subject_1
<Subject: C Programming>
>>> subject_1.course
<Course: BCA>

subject_1.course return course object which is mapped to that particular subject-object.

Let us take this even further and add some more courses and subjects so that we can have plenty of data to query.

>>> course = Course.objects.create(course_name="BBA")
>>> print(course)
BBA
>>> subject_1 = Subject.objects.create(course=course,subject_name="Business Administration")
>>> subject_2 = Subject.objects.create(course=course,subject_name="Economics")
>>> subject_3 = Subject.objects.create(course=course,subject_name="Accounting")
>>> subject_4 = Subject.objects.create(course=course,subject_name="Introduction to Taxation")
>>> subject_5 = Subject.objects.create(course=course,subject_name="Business Marketing") 

Now there is a new course BBA which has five different subjects.

Retrieving subjects of a particular course

>>> subjects=Subject.objects.filter(course__course_name__exact="BBA")
>>> print(subjects)
<QuerySet [<Subject: Business Administration>, <Subject: Economics>, <Subject: Accounting>, <Subject: Introduction to Taxation>, <Subject: Business Marketing>]>

# or other way
>>> subjects_1=Subject.objects.filter(course=Course.objects.get(pk=1))
>>> print(subjects_1)
<QuerySet [<Subject: C Programming>, <Subject: DataStructures using C>, <Subject: Visual Programming>]>
>>> 

By querying we get Queryset list of subjects which belong to course BBA.in above example we have specified two ways of retrieving data but they always return the same queryset.

Note

__excat and = are similarly were =(equal to ) calls __excat explicitly.

Next is to add students to course. A student must be enrolled in only one course and there will be many numbers of students who are enrolled in the same course.
So there is ForeignKey relationship between Course and Student model.

from datetime import datetime, date

>>> bba_course = Course.objects.get(course_name__contains="BBA")
>>> bca_course = Course.objects.get(course_name__contains="BCA")

students_list = [
    {'name':"Rakshit", 'course':bba_course, 'joining_date':"2018-02-21"},
    {'name':"Amar", 'course':bba_course, 'joining_date':"2019-03-05"},
    {'name':"Suresh", 'course':bca_course, 'joining_date':"2019-05-15"},
    {'name':"Kiran", 'course':bca_course, 'joining_date':"2018-02-05"},
    {'name':"Vasudev", 'course':bca_course, 'joining_date':"2018-06-18"},
    {'name':"Prakash", 'course':bba_course, 'joining_date':"2018-08-12"},
    {'name':"Naresh", 'course':bba_course, 'joining_date':"2018-11-25"},
];

for student in  students_list:
    students_data = Student.objects.create(**student)

We can also create objects using a dictionary. The students_list is a list which has student data as dictionary iteration student list over
Student.objects.create(**student) inserts a new record to in each iteration. In our tables, we have added four students from BBA and three students from BCA.

Get subjects taken by a student

from query_sets.models import Course, Subject, Student
>>> student_course = Student.objects.get(pk=2)
>>> print(student_course)
Amar
>>> print(student_course.course)
BBA
>>> Subject.objects.filter(course=student_course.course)
<QuerySet [<Subject: Business Administration>, <Subject: Economics>, <Subject: Accounting>, <Subject: Introduction to Taxation>, <Subject: Business Marketing>]>

Get subjects of all students

students = Student.objects.all()
for student in students:
    student.subjects = Subject.objects.filter(course=student.course)
print(students)
>>> print(students)
<QuerySet [<Student: Rakshit>, <Student: Amar>, <Student: Suresh>, <Student: Kiran>, <Student: Vasudev>, <Student: Prakash>, <Student: Naresh>]>
>>> print(students[0].subjects)
<QuerySet [<Subject: Business Administration>, <Subject: Economics>, <Subject: Accounting>, <Subject: Introduction to Taxation>, <Subject: Business Marketing>]>
>>> print(students[2].subjects)
<QuerySet [<Subject: C Programming>, <Subject: DataStructures using C>, <Subject: Visual Programming>]>
>>> 

Inner Join

It is possible to join two tables in Django. For this, we make use of the select_related() method.

>>> a1=Subject.objects.select_related('course')
>>> print(a1)
<QuerySet [<Subject: C Programming>, <Subject: DataStructures using C>, <Subject: Visual Programming>, <Subject: Business Administration>, <Subject: Economics>, <Subject: Accounting>, <Subject: Introduction to Taxation>, <Subject: Business Marketing>]>
>>> print(a1.query)
SELECT `subjects`.`id`, `subjects`.`course_id`, `subjects`.`subject_name`, `subjects`.`created_at`, `subjects`.`updated_at`, `courses`.`id`, `courses`.`course_name`, `courses`.`course_desc`, `courses`.`created_at`, `courses`.`updated_at` FROM `subjects` INNER JOIN `courses` ON (`subjects`.`course_id` = `courses`.`id`)

>>> a2=Subject.objects.filter(course__course_name__exact="BBA")
>>> print(a2)
<QuerySet [<Subject: Business Administration>, <Subject: Economics>, <Subject: Accounting>, <Subject: Introduction to Taxation>, <Subject: Business Marketing>]>
>>> print(a2.query)
SELECT `subjects`.`id`, `subjects`.`course_id`, `subjects`.`subject_name`, `subjects`.`created_at`, `subjects`.`updated_at` FROM `subjects` INNER JOIN `courses` ON (`subjects`.`course_id` = `courses`.`id`) WHERE `courses`.`course_name` = BBA
>>> 

Subject.objects.select_related('course') return a list of queryset objects where course_id matches to both tables. We can view raw MySQL query by calling .query property to object a1.

In the next example, we filter subjects by course_name using double underscore ( __ ).
First, we specify <model_name in small letters>__<model field name>__<query attributes such as exact, contain or etc>.

Note

You can find complete documentation regarding Django querysets

Conclusion

Till here we have the lead foundation for Querysets Fundamentals to learn more go to next part 2 of QuerySet Fundamentals. If you have any doubts please mention in the comment section and we’ll reach you soon and we would also love to hear requests and your recommendations for new tutorials/posts.

Related Posts

Summary
Review Date
Reviewed Item
Django Querysets | One To One Foreign Key, Inner Joins, Query Filtering
Author Rating
51star
1star1star1star1star
Software Name
Django Web Framework
Software Name
Windows Os, Mac Os, Ubuntu Os
Software Category
Web Development