Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Filter the prefetch_related queryset

I am trying to reduce my complexity by doing the following. I am trying to get all the teachers in active classrooms.

teacher/models.py:

Teacher(models.Model):
    name = models.CharField(max_length=300)


classroom/models.py:

Classroom(models.Model):
    name = models.CharField(max_length=300)
    teacher = models.ForeignKey(Teacher)
    students = models.ManyToManyField(Student)
    status = models.CharField(max_length=50)

admin/views.py

teachers = Teacher.objects.prefetch_related(Prefetch('classroom_set',queryset=Classroom.objects.filter(status='Active'))


for teacher in teachers:
    classrooms = teacher.all()
    # run functions

By doing this I get teachers with classrooms. But it also returns teachers with no active classrooms(empty list) which I don't want. Because of this, I have to loop around thousands of teachers with empty classroom_set. Is there any way I can remove those teachers whose classroom_set is [ ]?

This is my original question - Django multiple queries with foreign keys

Thanks

like image 501
Ankit Singh Avatar asked Oct 11 '18 09:10

Ankit Singh


People also ask

What is Prefetch_related in Django?

In Django, select_related and prefetch_related are designed to stop the deluge of database queries that are caused by accessing related objects. In this article, we will see how it reduces the number of queries and make the program much faster.

What is Django Queryset?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.


1 Answers

If you want all teachers with at least one related active class, you do not need to prefetch these, you can filter on the related objects, like:

Teacher.objects.filter(class__status='Active').distinct()

If you want to filter the classroom_set as well, you need to combine filtering as well as .prefetch_related:

from django.db.models import Prefetch

Teacher.objects.filter(
    class__status='Active'
).prefetch_related(
    Prefetch('class_set', queryset=Class.objects.filter(status='Active'))
).distinct()

Here we thus will filter like:

SELECT DISTINCT teacher.*
FROM teacher
JOIN class on class.teacher_id = teacher.id
WHERE class.status = 'Active'
like image 123
Willem Van Onsem Avatar answered Sep 23 '22 12:09

Willem Van Onsem