Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for DRF 3.15 nested SimpleRouter.use_regex_path = False #342

Open
Gibsondz opened this issue Apr 29, 2024 · 1 comment
Open

Support for DRF 3.15 nested SimpleRouter.use_regex_path = False #342

Gibsondz opened this issue Apr 29, 2024 · 1 comment

Comments

@Gibsondz
Copy link

I know that 3.15 is not part of the the supported versions of DRF yet but I thought this would be useful to bring up. This is my first time doing something like this so please let me know if it's off base.

Ran into this when I was looking to use a custom url converter and attempting to apply the converter to nested URLs using NestedSimpleRouter

When use_regex_path=False on SimpleRouter it will strip the regex ^ and $ characters from the router routes causing the following line to not properly pre-pend the parent_prefix to the route.

DRF 3.15 regex strip:

        if use_regex_path:
            self._base_pattern = '(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})'
            self._default_value_pattern = '[^/.]+'
            self._url_conf = re_path
        else:
            self._base_pattern = '<{lookup_value}:{lookup_prefix}{lookup_url_kwarg}>'
            self._default_value_pattern = 'str'
            self._url_conf = path
            # remove regex characters from routes
            _routes = []
            for route in self.routes:
                url_param = route.url
                if url_param[0] == '^':
                    url_param = url_param[1:]
                if url_param[-1] == '$':
                    url_param = url_param[:-1]

NestedMixin's route replacement for regex ^ character
route_contents['url'] = route.url.replace('^', '^' + escaped_parent_regex)

The '^' does not exist in this case and the router fails silently not pre-pending any parent to the route.

Example to reproduce is to use DRF 3.15 and set up the following urls.py:

# urls.py
from rest_framework_nested import routers
from views import DomainViewSet, NameserverViewSet
(...)

router = routers.SimpleRouter(use_regex_path=False)
router.register(r'domains', DomainViewSet, )

domains_router = routers.NestedSimpleRouter(router, r'domains', lookup='domain', use_regex_path=False)
domains_router.register(r'nameservers', NameserverViewSet, basename='domain-nameservers')

urlpatterns = [
    path(r'', include(router.urls)),
    path(r'', include(domains_router.urls)),
]

I made quick and dirty fix locally by doing something like below:

class NestedMixin(object):
    def __init__(self, parent_router, parent_prefix, *args, **kwargs):
        self.parent_router = parent_router
        self.parent_prefix = parent_prefix
        self.nest_count = getattr(parent_router, 'nest_count', 0) + 1
        self.nest_prefix = kwargs.pop('lookup', 'nested_%i' % self.nest_count) + '_'
        self.use_regex_path = kwargs.get('use_regex_path', True)
        for route in self.routes:
            route_contents = route._asdict()

            # This will get passed through .format in a little bit, so we need
            # to escape it
            escaped_parent_regex = self.parent_regex.replace('{', '{{').replace('}', '}}')

            if self.use_regex_path:
                route_contents['url'] = route.url.replace('^', '^' + escaped_parent_regex)
            else:
                route_contents['url'] = escaped_parent_regex + route_contents['url']
            nested_routes.append(type(route)(**route_contents))
@AlexeyBurkov
Copy link

@Gibsondz, thanks a lot.

Faced the same issue.
Solution looks nice enough. Works for me.

I'd recommend forking the repo and creating a pull request with the solution (and mention the issue in it), that would be easier to understand, imho.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants