Search code examples
pythondjangoprefetch

django filter a prefetch_related queryset


I am trying to use prefetch_related with a model with foreign key because I then need to query the database within a loop.

models.py

class SelfEvaluatedStatement(models.Model):
    evaluation_statement = models.ForeignKey(EvaluationStatement, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    rating = models.IntegerField(default=0)

views.py

queryset = SelfEvaluatedStatement.objects.prefetch_related(
        'evaluation_statement__sku__topic__subject', 'evaluation_statement__sku__level'
    ).filter(
        evaluation_statement__sku__topic__subject=subject,
        evaluation_statement__sku__level=level
    )

for student_user in student_users:
    red_count = queryset.filter(user=student_user, rating=1).count()

However, this hits the database with a new query each time I iterate through the loop. Is it possible to filter a queryset which has been prefetched, or am I thinking about this incorrectly?


Solution

  • So I completely re-thought this. Not sure if this is necessarily the best solution, but it is much faster. The reason the query was so slow was because of the filter on 2 primary keys. The query was being run for each of the students in a class, so maybe 20-30 times which meant it took > 30 seconds.

    Solution

    I reduced it all into a single query executed prior to the loop, and pulled the data for all of the student users in that single query. I converted this to a values list.

    queryset = SelfEvaluatedStatement.objects.filter(
            evaluation_statement__sku__topic__subject=subject,
            evaluation_statement__sku__level=level,
            user__in=student_users
        )
    
    my_values = list(queryset.values_list('user__username', 'rating'))
    

    I then used Python to iterate through the values list and this solution was significantly faster because of only 1 database query.