Skip to content

Commit 8d0dbc8

Browse files
committed
Fix lookup_url_kwarg handling in viewsets.
The ``lookup_url_kwarg`` is intended to set the name of a field in the URL regexps when using custom ``lookup_field``, but the routers ignore it altogether.
1 parent a02098b commit 8d0dbc8

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

rest_framework/routers.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,15 @@ def get_lookup_regex(self, viewset, lookup_prefix=''):
218218
219219
https://github.com/alanjds/drf-nested-routers
220220
"""
221-
base_regex = '(?P<{lookup_prefix}{lookup_field}>{lookup_value})'
221+
base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})'
222222
# Use `pk` as default field, unset set. Default regex should not
223223
# consume `.json` style suffixes and should break at '/' boundaries.
224224
lookup_field = getattr(viewset, 'lookup_field', 'pk')
225+
lookup_url_kwarg = getattr(viewset, 'lookup_url_kwarg', None) or lookup_field
225226
lookup_value = getattr(viewset, 'lookup_value_regex', '[^/.]+')
226227
return base_regex.format(
227228
lookup_prefix=lookup_prefix,
228-
lookup_field=lookup_field,
229+
lookup_url_kwarg=lookup_url_kwarg,
229230
lookup_value=lookup_value
230231
)
231232

tests/test_routers.py

+38
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ class NoteViewSet(viewsets.ModelViewSet):
3232
lookup_field = 'uuid'
3333

3434

35+
class KWargedNoteViewSet(viewsets.ModelViewSet):
36+
queryset = RouterTestModel.objects.all()
37+
serializer_class = NoteSerializer
38+
lookup_field = 'text__contains'
39+
lookup_url_kwarg = 'text'
40+
41+
3542
class MockViewSet(viewsets.ModelViewSet):
3643
queryset = None
3744
serializer_class = None
@@ -40,13 +47,17 @@ class MockViewSet(viewsets.ModelViewSet):
4047
notes_router = SimpleRouter()
4148
notes_router.register(r'notes', NoteViewSet)
4249

50+
kwarged_notes_router = SimpleRouter()
51+
kwarged_notes_router.register(r'notes', KWargedNoteViewSet)
52+
4353
namespaced_router = DefaultRouter()
4454
namespaced_router.register(r'example', MockViewSet, base_name='example')
4555

4656
urlpatterns = [
4757
url(r'^non-namespaced/', include(namespaced_router.urls)),
4858
url(r'^namespaced/', include(namespaced_router.urls, namespace='example')),
4959
url(r'^example/', include(notes_router.urls)),
60+
url(r'^example2/', include(kwarged_notes_router.urls)),
5061
]
5162

5263

@@ -177,6 +188,33 @@ def test_urls_limited_by_lookup_value_regex(self):
177188
self.assertEqual(expected[idx], self.urls[idx].regex.pattern)
178189

179190

191+
class TestLookupUrlKwargs(TestCase):
192+
"""
193+
Ensure the router honors lookup_url_kwarg.
194+
195+
Setup a deep lookup_field, but map it to a simple URL kwarg.
196+
"""
197+
urls = 'tests.test_routers'
198+
199+
def setUp(self):
200+
RouterTestModel.objects.create(uuid='123', text='foo bar')
201+
202+
def test_custom_lookup_url_kwarg_route(self):
203+
detail_route = kwarged_notes_router.urls[-1]
204+
detail_url_pattern = detail_route.regex.pattern
205+
self.assertIn('^notes/(?P<text>', detail_url_pattern)
206+
207+
def test_retrieve_lookup_url_kwarg_detail_view(self):
208+
response = self.client.get('/example2/notes/fo/')
209+
self.assertEqual(
210+
response.data,
211+
{
212+
"url": "http://testserver/example/notes/123/",
213+
"uuid": "123", "text": "foo bar"
214+
}
215+
)
216+
217+
180218
class TestTrailingSlashIncluded(TestCase):
181219
def setUp(self):
182220
class NoteViewSet(viewsets.ModelViewSet):

0 commit comments

Comments
 (0)