Get slug name list by url path name

I am reverse-engineering django urlpatterns. For my purpose, I need to dynamically know the list of slug names developers chose to use within url.

Example:

path("<slug:membership_slug>/<slug:parent_slug>/data/", rzd.ReportingUnitDataView.as_view(), name="hierarchy.item.data"),

So, in the world, where everyone writes perfect code, my function whould take "hierarcy.item.data" and spit out ["membership_slug", "parent_slug"]

I looked at the reverse function, hoping it would return something useful without kwargs, but it does not. Have been googling like Neo, but to no avail. But the hope does not leave my heart... somewhere django should hold all that urlpatterns stuff! I still believe.

Perhaps you can at suggest how to get a hold of list of urls, even if in the raw format, that would already be a help. Thank you.

Search for book called Django 2x scopes this book hold every thing related to django best practices and of course the urls part.

This book will help you to understand more how django developers think.

Happy hacking 🙃

I think you're best guess is to write a Regex..

From what I've found in the source code they use _lazy_re_compile(r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>') which can be found in urls\resolvers.py in _route_to_regex

this is what I've come up with after butchering the source code

def geturlnamedarguments(route):
    from django.utils.regex_helper import _lazy_re_compile
    named_arguments = []
    while True:
        match = _lazy_re_compile(r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>[^>]+)>').search(route)
        if not match:
            break
        route = route[match.end():]
        parameter = match['parameter']
        named_arguments.append(parameter)
    return named_arguments

You can also get the raw URL route as a string by doing

urlpatterns[index].pattern._route

You can find the URLPattern Object also in urls\resolvers.py if you want to play around with it.. I never found a place where they have the names in a raw format

Solved, It occurred to me, that I can just include urls.py and parse it out myself :)

from myapp import urls


class UrlPatterns:

    @staticmethod
    def _get_params(s):
        items = []
        is_exp = False
        is_prefix = False
        type = ''
        name = ''
        for n in range(len(s)):
            if not is_exp:
                if s[n] == '<':
                    is_exp = True
                    is_prefix = True
                    type = ''
            elif is_prefix:
                if s[n] == ':':
                    is_prefix = False
                else:
                    type += s[n]
            else:
                if s[n] == '>':
                    is_exp = False
                    items.append({
                        'type': type,
                        'name': name
                    })
                    name = ''
                else:
                    name += s[n]

        return items

    @staticmethod
    def _find_pattern(url_name):
        for url in urls.urlpatterns:
            if url.name == url_name:
                return str(url.pattern)
        return None

    @staticmethod
    def get_required_params(url_name):
        url_pattern = UrlPatterns._find_pattern(url_name)
        if url_pattern:
            return UrlPatterns._get_params(url_pattern)
        return None
Back to Top