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