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?
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.