Skip to content

Commit

Permalink
Fix lookup_value_regex for nesting over two levels deep. (#192)
Browse files Browse the repository at this point in the history
Consider every parent's (not just the last one's) `lookup_value_regex` attribute
when building the URL prefix.
  • Loading branch information
ivoscc authored and auvipy committed Sep 7, 2017
1 parent 3dbb183 commit 97490d4
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
2 changes: 1 addition & 1 deletion rest_framework_extensions/routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ def get_parent_prefix(self, parents_query_lookups):
prefix = '/'
current_item = self
i = len(parents_query_lookups) - 1
parent_lookup_value_regex = getattr(self.parent_viewset, 'lookup_value_regex', '[^/.]+')
while current_item:
parent_lookup_value_regex = getattr(current_item.parent_viewset, 'lookup_value_regex', '[^/.]+')
prefix = '{parent_prefix}/(?P<{parent_pk_kwarg_name}>{parent_lookup_value_regex})/{prefix}'.format(
parent_prefix=current_item.parent_prefix,
parent_pk_kwarg_name=compose_parent_pk_kwarg_name(parents_query_lookups[i]),
Expand Down
83 changes: 82 additions & 1 deletion tests_app/tests/unit/routers/nested_router_mixin/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
UserViewSet,
GroupViewSet,
PermissionViewSet,
CustomRegexUserViewSet,
CustomRegexGroupViewSet,
CustomRegexPermissionViewSet,
)


Expand All @@ -19,6 +22,21 @@ def get_parent_lookup_regex(self, value):
return get_lookup_allowed_symbols(compose_parent_pk_kwarg_name(value), force_dot=True)
# return '(?P<{0}>[^/.]+)'.format(compose_parent_pk_kwarg_name(value))

def get_custom_regex_lookup(self, pk_kwarg_name, lookup_value_regex):
""" Build lookup regex with custom regular expression. """
return '(?P<{pk_kwarg_name}>{lookup_value_regex})'.format(
pk_kwarg_name=pk_kwarg_name,
lookup_value_regex=lookup_value_regex
)

def get_custom_regex_parent_lookup(self, parent_pk_kwarg_name,
parent_lookup_value_regex):
""" Build parent lookup regex with custom regular expression. """
return self.get_custom_regex_lookup(
compose_parent_pk_kwarg_name(parent_pk_kwarg_name),
parent_lookup_value_regex
)

def test_one_route(self):
router = ExtendedSimpleRouter()
router.register(r'users', UserViewSet, 'user')
Expand Down Expand Up @@ -111,4 +129,67 @@ def test_nested_route_depth_3(self):
self.get_parent_lookup_regex('group'),
self.get_lookup_regex('pk')
),
)
)

def test_nested_route_depth_3_custom_regex(self):
"""
Nested routes with over two level of depth should respect all parents'
`lookup_value_regex` attribute.
"""
router = ExtendedSimpleRouter()
(
router.register(r'users', CustomRegexUserViewSet, 'user')
.register(r'groups', CustomRegexGroupViewSet, 'users-group',
parents_query_lookups=['user'])
.register(r'permissions', CustomRegexPermissionViewSet,
'users-groups-permission', parents_query_lookups=[
'group__user',
'group',
]
)
)

# custom regex configuration
user_viewset_regex = CustomRegexUserViewSet.lookup_value_regex
group_viewset_regex = CustomRegexGroupViewSet.lookup_value_regex
perm_viewset_regex = CustomRegexPermissionViewSet.lookup_value_regex

# test user list
self.assertEqual(router.urls[0].name, 'user-list')
self.assertEqual(router.urls[0]._regex, r'^users/$')

# test user detail
self.assertEqual(router.urls[1].name, 'user-detail')
self.assertEqual(router.urls[1]._regex, r'^users/{0}/$'.format(
self.get_custom_regex_lookup('pk', user_viewset_regex))
)

# test users group list
self.assertEqual(router.urls[2].name, 'users-group-list')
self.assertEqual(router.urls[2]._regex, r'^users/{0}/groups/$'.format(
self.get_custom_regex_parent_lookup('user', user_viewset_regex)
)
)
# test users group detail
self.assertEqual(router.urls[3].name, 'users-group-detail')
self.assertEqual(router.urls[3]._regex, r'^users/{0}/groups/{1}/$'.format(
self.get_custom_regex_parent_lookup('user', user_viewset_regex),
self.get_custom_regex_lookup('pk', group_viewset_regex)
),
)
# test users groups permission list
self.assertEqual(router.urls[4].name, 'users-groups-permission-list')
self.assertEqual(router.urls[4]._regex, r'^users/{0}/groups/{1}/permissions/$'.format(
self.get_custom_regex_parent_lookup('group__user', user_viewset_regex),
self.get_custom_regex_parent_lookup('group', group_viewset_regex),
)
)

# test users groups permission detail
self.assertEqual(router.urls[5].name, 'users-groups-permission-detail')
self.assertEqual(router.urls[5]._regex, r'^users/{0}/groups/{1}/permissions/{2}/$'.format(
self.get_custom_regex_parent_lookup('group__user', user_viewset_regex),
self.get_custom_regex_parent_lookup('group', group_viewset_regex),
self.get_custom_regex_lookup('pk', perm_viewset_regex)
),
)
15 changes: 15 additions & 0 deletions tests_app/tests/unit/routers/nested_router_mixin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,18 @@ class GroupViewSet(ModelViewSet):

class PermissionViewSet(ModelViewSet):
model = PermissionModel


class CustomRegexUserViewSet(ModelViewSet):
lookup_value_regex = 'a'
model = UserModel


class CustomRegexGroupViewSet(ModelViewSet):
lookup_value_regex = 'b'
model = GroupModel


class CustomRegexPermissionViewSet(ModelViewSet):
lookup_value_regex = 'c'
model = PermissionModel

0 comments on commit 97490d4

Please sign in to comment.