Django get url regex по имени

У меня есть случай, когда я определил некоторые шаблоны url Django, и теперь я хочу получить регулярное выражение, связанное с данным шаблоном. Я хочу, потому что я хочу передать эти регулярные выражения клиенту, чтобы я мог проверять URL-адреса на клиенте (я говорю об обработке истории браузера) и запускать соответствующие обработчики (в JavaScript), когда есть совпадение.

Например, если у меня есть:

# urls.py
urlpatterns = patterns("",
    url(r"^$", Index.as_view(), name="index"),
    url(r"^user/", include("User.urls", namespace="User")),
)

# User/urls.py
urlpatterns = patterns("",
    url(r"^profile/(?P<slug>.*)$", GetProfile.as_view(), name="get_profile")
)

тогда мне нужна следующая функция:

>>> get_regex("User:get_profile")
'^user/profile/(?P<slug>.*)$'

(или, тем не менее, Django переводит его). Обратите внимание, что я использую пространства имен. Есть идеи? Django1.5.

Также мне удалось написать функцию, которая возвращает объект urlpattern, связанный с переданным именем, однако url.regex.pattern возвращает '^profile/(?P<slug>.*)$. Итак, вы можете видеть, что нет ведущего ^user/.

Ответ 1

Итак, я пробовал несколько вещей, и, наконец, я придумал свое решение. Сначала я конвертирую urlpatterns в форму, которую JavaScript понимает:

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

Затем я вызываю generate_paths(urlpatterns), JSON-stringify результат и передаю его JavaScript (обратите внимание, что в JavaScript мне нужно преобразовать регулярные выражения как строки в объекты RegExp). В JavaScript у меня есть

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...
};

Теперь в // do something... я могу что-то сделать с names и args. Например, я могу хранить словарь именованных обработчиков, я могу найти обработчик (на основе names) и называть его args.

Это решение, которое работает для меня. Преобразование urlpatterns в шаблоны JavaScript может быть не идеальным (поскольку converter кажется слишком упрощенным), но он работает в самых простых случаях.

Ответ 2

Существует несколько реализаций javascript reverse.

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

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

Это не регулярное выражение, но вы можете проверить URL-адреса в своем клиентском коде так же, как на сервере, так что это еще лучше, на мой взгляд.

РЕДАКТИРОВАТЬ. Поскольку вам нужно игнорировать аргументы URL, вы можете получить представление от источника django-js здесь. Он уже удаляет необязательные URL-адреса, поэтому он, вероятно, очень похож на то, что вы описываете.

Этот код выполняет итерацию по каждому шаблону, удаляя ?P из каждого аргумента subregex, поэтому вы можете просто заменить их на .*.

Суть в том, что у вас есть в этом источнике любое регулярное выражение, которое вам, возможно, понадобится для выполнения вашей реализации. См. Глобальные шаблоны в строках 24-29.

Ответ 3

Попробуйте следующее:

from django.core.urlresolvers import get_resolver

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

Ответ 4

Насколько я понял, вы хотите иметь возможность возвращать выражение регулярного выражения (а не URL) данного представления.

Это мой эскиз решения:

Функция url возвращает экземпляр RegexURLResolver. Этот класс хранит регулярное выражение, потому что он вызывает LocaleRegexProvider в __init__ (в этой строке и эта строка).

Итак, я думаю, что вы можете

  • обратный поиск в представлении плюс пространство имен
  • получить кортеж этого представления из кортежа кортежей urlpatterns
  • return _regex первого аргумента, LocaleRegexProvider._regex (или regex()) кортежа, соответствующего представлению.

Я не уверен, что это работает (не проверено), ни то, что это лучшее решение, но по крайней мере у вас есть ссылки на то, где Django хранит регулярное выражение.

Ответ 5

Не ответ, но может быть полезен для кого-то другого, смотрящего на это.

Далее генерируется список всех, полный URL-шаблонов в проекте Django, в том числе для вложенных URLRegexResolvers, на основе кода @Freakish.

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))