2013-09-06 12 views
10

Mam przypadek, w którym zdefiniowałem niektóre wzorce adresów URL Django, a teraz chcę odzyskać wyrażenie regularne powiązane z danym wzorcem. Chcę tego, ponieważ chcę przekazać te wyrażeń regularnych do klienta, aby móc również sprawdzać adresy URL w kliencie (mówię o manipulowaniu historią po stronie przeglądarki) i uruchamiać odpowiednie programy obsługi (w języku JavaScript), gdy istnieje dopasowanie.Django pobierz zapytanie do regex o nazwie

Na przykład, jeśli mieć

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

to muszę się następującą funkcję:

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

(lub przekłada się jednak Django). Zwróć uwagę, że używam przestrzeni nazw. Jakieś pomysły? Django1.5.

Udało mi się również napisać funkcję, która zwraca obiekt urlpattern powiązany z nazwą przekazaną, jednak wykonanie url.regex.pattern zwraca '^profile/(?P<slug>.*)$. Tak więc, jak widać, nie ma wiodącego .

+0

można pokazać kawałek views.py pomocne mogłoby być – drabo2005

+0

@ drabo2005 Jak miałoby to być pomocne? Treść nie ma znaczenia. – freakish

+0

@freakish Po prostu wskaźnik: jeśli spojrzysz na klasę 'RegexURLResolver' w' django.core.urlresolvers.py', ma ona właściwość 'reversed_dict'. Powinien mieć wzór, którego szukasz. Spójrz na linię 385, ten sam plik. – Germano

Odpowiedz

2

Więc próbowałem kilku rzeczy i wreszcie wymyśliłem własne rozwiązanie. Najpierw przekonwertować urlpatterns w formie, która JavaScript rozumie:

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 

Potem zadzwoń generate_paths(urlpatterns), JSON-stringify wynik i przekazać go do JavaScript (zauważ, że w JavaScript muszę konwertować wyrażeń regularnych jako ciągów RegExp obiektów) . W JavaScript mam

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

Teraz w // do something... mogę coś zrobić z names i args. Na przykład mogę przechowywać słownik nazwanych procedur obsługi, mogę wyszukać program obsługi (na podstawie names) i zadzwonić pod numer args.

To jest rozwiązanie, które działa dla mnie. Konwersja urlpatterns na wzorce JavaScript może nie być idealna (ponieważ converter wydaje się nieco zbyt uproszczona), ale działa w najprostszych przypadkach.

2

Istnieje kilka implementacji javascript reverse.

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

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

To nie regex, ale można przetestować adresy URL w kodzie klienta jak to zrobić na serwerze, więc to nawet lepiej moim zdaniem.

EDYCJA: Ponieważ musisz zignorować argumenty URL, możesz uzyskać pomysł ze źródła django-js here. Usuwa już opcjonalne argumenty URL, więc prawdopodobnie jest bardzo podobny do tego, co opisujesz.

Kod jest powtarzany dla każdego wzorca usuwającego ?P z każdego argumentu subregex, więc można je po prostu zastąpić .*.

Chodzi o to, że masz w tym źródle każde regex, które możesz potrzebować do wykonania. Zobacz globalne wzorce w liniach 24-29.

+0

To nie moja sprawa. Nie próbuję odwracać adresów URL. Próbuję uzyskać wyrażenie regularne, aby można było uruchomić procedurę obsługi, jeśli adres URL pasuje do wyrażenia regularnego w kodzie JavaScript. – freakish

+0

Ale jaka jest różnica? Nie możesz po prostu zrobić 'if (url === reverse ('name'))' –

+0

Różnica polega na tym, że URL może zawierać dodatkowe argumenty, takie jak 'slug' w przykładzie, który pokazałem powyżej. Więc podany adres URL to (na przykład) '/ user/profile/root' i co nazwałbyś' reverse'? Muszę dopasować go do regex. – freakish

1

Spróbuj tego:

from django.core.urlresolvers import get_resolver 

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

Po pierwsze: 'resolver.reverse_dict' zapełni się, gdy zostanie wywołane' reverse' (co może się w ogóle nie wydarzyć w moim przypadku). Po drugie: ten sam problem: nie zawiera całego wzorca url (prefiks '^ użytkownik /' będzie nieobecny z powodu 'url (..., include (...))'). – freakish

+0

@ Dziwaczny Próbowałem uruchomić kod w mojej powłoce i otrzymałem cały wzór z prefiksem. Nie dostaję jednak "^". Czy jesteś pewien, że 'reverse_dict' nie jest zapełniany lazily za każdym razem, gdy zostanie wywołany? – Germano

+0

Właściwie to nie mogłem wypełnić go '' get_profile' route. Czy na pewno używasz 'urlpatterns' z' include'? Ten obiekt 'resolver' wydaje się przechowywać tylko wzorce URL najwyższego poziomu. Problem polega na wzorach, które są zawarte w innych wzorach. – freakish

0

O ile zrozumiałem, chcesz być w stanie powrócić regex wyrażenie (a nie URL) danego widoku.

To mój szkic rozwiązania:

Funkcja url zwraca instancję RegexURLResolver. Ta klasa przechowuje wyrażenie regularne, ponieważ wywołuje LocaleRegexProvider na __init__ (i this line).

Tak, myślę, że można

  1. odwrotnego wyszukiwania pogląd plusa nazw
  2. uzyskać krotki tego widoku z krotka krotek urlpatterns
  3. powrotnej _regex pierwszego argumentu LocaleRegexProvider._regex (lub regex()) krotki odpowiedniej do widoku.

Nie jestem pewien, czy to działa (nie testowano), ani że jest to najlepsze rozwiązanie, ale przynajmniej masz kilka linków na temat tego, gdzie Django przechowuje regex.

+0

Tak, to właśnie rozumiałem przez "Udało mi się napisać funkcję". Niestety "_regex" (który wydaje się być taki sam jak ".regex.pattern") zawiera tylko informację o własnym wyrażeniu regularnym (zdefiniowanym w 'url (...)'), a nie całej ścieżce (nie obejmuje ' url (..., include (...)) "). – freakish

0

Nie jest to odpowiedź, ale może być przydatna dla kogoś, kto na nią patrzy.

Poniższa generuje listę wszystkich, kompletnych wzorców adresów URL w projekcie Django, w tym dla zagnieżdżonych URLRegexResolvers, na podstawie kodu @ 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)) 
Powiązane problemy