Skip to content

Commit ab6f093

Browse files
committed
Prefetch awesome_count and has_user_awesomed
Previous version caused 2 extra queries for every dweet to generate "has_user_awesomed" (one user query and then a dweet query) and 1 extra query to generate the awesome_count. This commit achieves the same result in the main query instead, using the prefetch_related mechanism (at the cost of a more expensive main query with some JOINs)
1 parent a92b077 commit ab6f093

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

dwitter/serializers_v2.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ class DweetSerializer(serializers.ModelSerializer):
141141
remix_of = RemixOfSerializer(source='reply_to')
142142
remixes = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
143143

144-
awesome_count = serializers.SerializerMethodField()
145-
has_user_awesomed = serializers.SerializerMethodField()
144+
awesome_count = serializers.IntegerField()
145+
has_user_awesomed = serializers.BooleanField()
146146
author = UserSerializer()
147147
comments = CommentSerializer(many=True)
148148

@@ -160,9 +160,4 @@ class Meta:
160160
'has_user_awesomed',
161161
)
162162

163-
def get_has_user_awesomed(self, dweet):
164-
user = self.context['request'].user
165-
return dweet.likes.filter(pk=user.pk).exists()
166163

167-
def get_awesome_count(self, obj):
168-
return obj.likes.all().count()

dwitter/views_v2.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.contrib.auth.models import User
55

66
from django.db.models import Prefetch, Count
7+
from django.db.models.expressions import Exists, OuterRef
78
from django.utils import timezone
89

910
from rest_framework import mixins, viewsets, status
@@ -70,18 +71,30 @@ class DweetViewSet(mixins.RetrieveModelMixin,
7071
queryset = Dweet.objects.all().select_related(
7172
'author',
7273
).prefetch_related(
74+
Prefetch('reply_to', queryset=Dweet.objects.select_related('author')),
7375
'likes',
76+
Prefetch('remixes'),
7477
Prefetch('comments', queryset=Comment.objects.select_related('author'))
78+
).annotate(
79+
awesome_count=Count('likes')
7580
).order_by('-hotness')
81+
7682
serializer_class = DweetSerializer
7783

84+
def retrieve(self, request, pk):
85+
self.queryset = self.queryset.annotate(
86+
has_user_awesomed=Exists(Dweet.objects.filter(
87+
id=OuterRef('id'), likes__in=[request.user.id]))
88+
)
89+
90+
return super().retrieve(request, pk)
91+
7892
def create(self, request):
7993
code = request.data.get('code', '')
8094
if (length_of_code(code) > 140):
8195
raise ValidationError("Code longer than 140 characters")
8296

8397
remix_of_pk = request.data.get('remix_of', -1)
84-
8598
# Using filter().first() will return None if it doesn't exist
8699
# instead of raising a DoesNotExist exception
87100
remix_of = self.queryset.filter(pk=remix_of_pk).first()
@@ -130,6 +143,11 @@ def list(self, request):
130143
if order_by == '-awesome_count':
131144
self.queryset = self.queryset.annotate(awesome_count=Count('likes'))
132145

146+
self.queryset = self.queryset.annotate(
147+
has_user_awesomed=Exists(Dweet.objects.filter(
148+
id=OuterRef('id'), likes__in=[request.user.id]))
149+
)
150+
133151
self.queryset = self.queryset.order_by(order_by).filter(
134152
posted__gte=posted_after, posted__lt=posted_before, **filters)
135153

0 commit comments

Comments
 (0)