Skip to content

Commit 8dfd85b

Browse files
authored
Fix N+1 query problem in GET /api/v1/changesets/ (#744)
The DRF Serializer for the Changeset model was using obj.tags.filter() and obj.reasons.filter() to filter the lists of reasons and tags (only showing enabled ones to non-staff users). This had the probably unexpected consequence of generating an additional two database queries for each changeset in the resulting list. The reasons and tags related fields were being prefetched, but prefetching only works for iterating the entire relation. The fix for this problem is straightforward: instead of using .filter(), we can just filter the reasons and tags in Python. This allows the prefetching to work as intended and avoids the additional queries.
1 parent 7159e7a commit 8dfd85b

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

osmchadjango/changeset/serializers.py

+9-10
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,17 @@ class ChangesetSerializer(ChangesetSerializerToStaff):
5656
tags = SerializerMethodField()
5757

5858
def get_reasons(self, obj):
59-
return BasicSuspicionReasonsSerializer(
60-
obj.reasons.filter(is_visible=True),
61-
many=True,
62-
read_only=True
63-
).data
59+
# Using obj.reasons.filter() would generate a new query, which in the context
60+
# of ChangesetListAPIView would waste the prefetching we've done and cause
61+
# N+1 total queries. To avoid this, we instead filter the reasons in Python.
62+
visible_reasons = [reason for reason in obj.reasons.all() if reason.is_visible]
63+
return BasicSuspicionReasonsSerializer(visible_reasons, many=True, read_only=True).data
6464

6565
def get_tags(self, obj):
66-
return BasicTagSerializer(
67-
obj.tags.filter(is_visible=True),
68-
many=True,
69-
read_only=True
70-
).data
66+
# Filter the tags in Python rather than using obj.tags.filter() which would
67+
# generate a new query (see above)
68+
visible_tags = [tag for tag in obj.tags.all() if tag.is_visible]
69+
return BasicTagSerializer(visible_tags, many=True, read_only=True).data
7170

7271

7372
class UserWhitelistSerializer(ModelSerializer):

0 commit comments

Comments
 (0)