Search code examples
pythonmysqldjangopython-2.7prefetch

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


Solution

  • 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'