[Solved]-Django get url regex by name

2👍

So I’ve tried few things and finally I came up with my own solution. First I convert urlpatterns into a form which JavaScript understands:

import re
converter = re.compile(r"\?P<.*?>")

def recursive_parse(urlpatterns, lst):
    for pattern in urlpatterns:
        obj = {
            "pattern": converter.sub("", pattern.regex.pattern)
        }
        if hasattr(pattern, "name") and pattern.name is not None:
            obj["name"] = pattern.name
        if hasattr(pattern, "namespace"):
            obj["namespace"] = pattern.namespace

        if hasattr(pattern, "url_patterns"):
            if "urls" not in obj:
                obj["urls"] = []
            recursive_parse(pattern.url_patterns, obj["urls"])

        lst.append(obj)


def generate_paths(urlpatterns):
    paths = []
    recursive_parse(urlpatterns, paths)
    return paths

Then I call generate_paths(urlpatterns), JSON-stringify the result and pass it to JavaScript (note that in JavaScript I have to convert regular expressions as strings to RegExp objects). In JavaScript I have

var recursive_check = function(url, patterns, names, args) {
    var l = patterns.length;
    for (var i = 0; i < l; i++) {
        var pat = patterns[i],
            match = pat.pattern.exec(url);
        pat.lastIndex = 0;
        if (match) {
            names.push(pat.namespace || pat.name);
            var f = match.shift(),
                url = url.replace(f, ""),
                ml = match.length;
            for (var j = 0; j < ml; j++) {
                args.push(match[j]);
            }
            if (pat.urls) {
                recursive_check(url, pat.urls, names, args);
            }
            break;
        }
    }
};

var fire_handler = function(url) {
    var names = [], args = [];
    recursive_check(url, patterns, names, args);
    // do something...
};

Now in // do something... I can do something with names and args. For example I can keep a dictionary of named handlers, I can search for a handler (based on names) and call it with args.

That’s the solution that works for me. Converting urlpatterns to JavaScript patterns might not be perfect (since converter seems to be a bit too simplified) but it works in most simple cases.

2👍

There are several javascript reverse implementations out there.

http://djangojs.readthedocs.org/en/latest/djangojs.html#reverse-urls

https://github.com/version2/django-js-reverse

It’s not the regex, but you could test the urls in your client code just like you do in the server, so it’s even better in my opinion.

EDIT: Since you need to ignore URL arguments, you could get an idea from the source of django-js here. It already removes optional URL arguments, so it’s probably very similar to what you describe.

The code iterates over every pattern removing the ?P from each argument subregex so you could just replace them with .*.

The point is you have in that source every regex you could possibly need to do your implementation. See the global patterns in lines 24-29.

1👍

Try this:

from django.core.urlresolvers import get_resolver

resolver = get_resolver(None)
url = resolver.reversed_dict.getlist('get_profile')
if url:
    pattern = url[0][1]

1👍

Not an answer but might be useful to someone else looking at this.

The following generates a list of all, complete url patterns in the Django project, including for nested URLRegexResolvers, based on @Freakish’s code.

import re
from django.core.urlresolvers import get_resolver

converter = re.compile(r"\?P<.*?>")

def trim_leading_caret(s):
    return s[1:] if s.startswith('^') else s

def recursive_parse(urlpatterns, lst, prefix=None):
    for pattern in urlpatterns:
        path = (prefix or '') + trim_leading_caret(converter.sub("", pattern.regex.pattern))
        if hasattr(pattern, "url_patterns"):
            recursive_parse(pattern.url_patterns, lst, path)
        else:
            lst.append('^' + path)

def generate_paths(urlpatterns):
    paths = []
    recursive_parse(urlpatterns, paths)
    return paths

generate_paths(get_resolver(None))
👤Chris

0👍

As far as I understood, you want to be able to return the regex expression (and not the url) of a given view.

This is my sketch of solution:

The function url returns an instance of RegexURLResolver. This class does store the regex, because it calls LocaleRegexProvider on __init__ (in this line and this line).

So, I think that you can

  1. reverse search the view plus namespace
  2. get the tuple of that view from the tuple of tuples urlpatterns
  3. return _regex of the first argument, LocaleRegexProvider._regex (or regex()), of the tuple respective to the view.

I’m not sure this works (didn’t tested), neither that it is the best solution, but at least you have some links on where Django stores the regex.

Leave a comment