Skip to content

Commit a2f322d

Browse files
committed
REST: De-duplicate handling of nested resource URLs
These were all doing the same thing. Make things more generic. We also speed up test (inadvertently) by using the 'patch_id' attribute of the 'Check' model rather than 'patch.id', thus avoiding the JOIN. Signed-off-by: Stephen Finucane <stephen@that.guru> (cherry picked from commit 4470c13)
1 parent 2715377 commit a2f322d

File tree

4 files changed

+45
-47
lines changed

4 files changed

+45
-47
lines changed

patchwork/api/base.py

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from django.shortcuts import get_object_or_404
1010
from rest_framework import permissions
1111
from rest_framework.pagination import PageNumberPagination
12+
from rest_framework.relations import HyperlinkedIdentityField
1213
from rest_framework.response import Response
13-
from rest_framework.serializers import HyperlinkedIdentityField
1414
from rest_framework.serializers import HyperlinkedModelSerializer
1515
from rest_framework.utils.urls import replace_query_param
1616

@@ -122,52 +122,28 @@ def get_object(self):
122122
return get_object_or_404(queryset, **filter_kwargs)
123123

124124

125-
class CheckHyperlinkedIdentityField(HyperlinkedIdentityField):
126-
def get_url(self, obj, view_name, request, format):
127-
# Unsaved objects will not yet have a valid URL.
128-
if obj.pk is None:
129-
return None
130-
131-
return self.reverse(
132-
view_name,
133-
kwargs={
134-
'patch_id': obj.patch.id,
135-
'check_id': obj.id,
136-
},
137-
request=request,
138-
format=format,
139-
)
125+
class NestedHyperlinkedIdentityField(HyperlinkedIdentityField):
126+
"""A variant of HyperlinkedIdentityField that supports nested resources."""
140127

128+
def __init__(self, view_name, lookup_field_mapping, **kwargs):
129+
self.lookup_field_mapping = lookup_field_mapping
130+
super().__init__(view_name, **kwargs)
141131

142-
class CoverCommentHyperlinkedIdentityField(HyperlinkedIdentityField):
143132
def get_url(self, obj, view_name, request, format):
144133
# Unsaved objects will not yet have a valid URL.
145-
if obj.pk is None:
134+
if hasattr(obj, 'pk') and obj.pk in (None, ''):
146135
return None
147136

148-
return self.reverse(
149-
view_name,
150-
kwargs={
151-
'cover_id': obj.cover.id,
152-
'comment_id': obj.id,
153-
},
154-
request=request,
155-
format=format,
156-
)
157-
158-
159-
class PatchCommentHyperlinkedIdentityField(HyperlinkedIdentityField):
160-
def get_url(self, obj, view_name, request, format):
161-
# Unsaved objects will not yet have a valid URL.
162-
if obj.pk is None:
163-
return None
137+
kwargs = {}
138+
for (
139+
lookup_url_kwarg,
140+
lookup_field,
141+
) in self.lookup_field_mapping.items():
142+
kwargs[lookup_url_kwarg] = getattr(obj, lookup_field)
164143

165144
return self.reverse(
166145
view_name,
167-
kwargs={
168-
'patch_id': obj.patch.id,
169-
'comment_id': obj.id,
170-
},
146+
kwargs=kwargs,
171147
request=request,
172148
format=format,
173149
)

patchwork/api/check.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
from rest_framework.serializers import HyperlinkedModelSerializer
1515
from rest_framework.serializers import ValidationError
1616

17-
from patchwork.api.base import CheckHyperlinkedIdentityField
1817
from patchwork.api.base import MultipleFieldLookupMixin
18+
from patchwork.api.base import NestedHyperlinkedIdentityField
1919
from patchwork.api.base import CurrentPatchDefault
2020
from patchwork.api.embedded import UserSerializer
2121
from patchwork.api.filters import CheckFilterSet
@@ -25,7 +25,13 @@
2525

2626
class CheckSerializer(HyperlinkedModelSerializer):
2727

28-
url = CheckHyperlinkedIdentityField('api-check-detail')
28+
url = NestedHyperlinkedIdentityField(
29+
'api-check-detail',
30+
lookup_field_mapping={
31+
'patch_id': 'patch_id',
32+
'check_id': 'id',
33+
},
34+
)
2935
patch = HiddenField(default=CurrentPatchDefault())
3036
user = UserSerializer(default=CurrentUserDefault())
3137

patchwork/api/embedded.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
from rest_framework.serializers import SerializerMethodField
1717

1818
from patchwork.api.base import BaseHyperlinkedModelSerializer
19-
from patchwork.api.base import CheckHyperlinkedIdentityField
20-
from patchwork.api.base import CoverCommentHyperlinkedIdentityField
21-
from patchwork.api.base import PatchCommentHyperlinkedIdentityField
19+
from patchwork.api.base import NestedHyperlinkedIdentityField
2220
from patchwork import models
2321

2422

@@ -82,7 +80,13 @@ def get_web_url(self, instance):
8280
class CheckSerializer(SerializedRelatedField):
8381
class _Serializer(BaseHyperlinkedModelSerializer):
8482

85-
url = CheckHyperlinkedIdentityField('api-check-detail')
83+
url = NestedHyperlinkedIdentityField(
84+
'api-check-detail',
85+
lookup_field_mapping={
86+
'patch_id': 'patch_id',
87+
'check_id': 'id',
88+
},
89+
)
8690

8791
def to_representation(self, instance):
8892
data = super(CheckSerializer._Serializer, self).to_representation(
@@ -130,7 +134,13 @@ class Meta:
130134
class CoverCommentSerializer(SerializedRelatedField):
131135
class _Serializer(MboxMixin, WebURLMixin, BaseHyperlinkedModelSerializer):
132136

133-
url = CoverCommentHyperlinkedIdentityField('api-cover-comment-detail')
137+
url = NestedHyperlinkedIdentityField(
138+
'api-cover-comment-detail',
139+
lookup_field_mapping={
140+
'cover_id': 'cover_id',
141+
'comment_id': 'id',
142+
},
143+
)
134144

135145
class Meta:
136146
model = models.CoverComment
@@ -182,7 +192,13 @@ class Meta:
182192
class PatchCommentSerializer(SerializedRelatedField):
183193
class _Serializer(MboxMixin, WebURLMixin, BaseHyperlinkedModelSerializer):
184194

185-
url = PatchCommentHyperlinkedIdentityField('api-patch-comment-detail')
195+
url = NestedHyperlinkedIdentityField(
196+
'api-patch-comment-detail',
197+
lookup_field_mapping={
198+
'patch_id': 'patch_id',
199+
'comment_id': 'id',
200+
},
201+
)
186202

187203
class Meta:
188204
model = models.PatchComment

patchwork/tests/api/test_event.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def test_list_bug_335(self):
200200
for _ in range(3):
201201
self._create_events()
202202

203-
with self.assertNumQueries(33):
203+
with self.assertNumQueries(30):
204204
self.client.get(self.api_url())
205205

206206
def test_order_by_date_default(self):

0 commit comments

Comments
 (0)