Używasz {% url ??? %} w szablonach django

84

Dużo szukałem w Google w poszukiwaniu odpowiedzi, jak używać tagu „url” w szablonach tylko po to, aby znaleźć wiele odpowiedzi mówiących „Po prostu wstaw go do szablonu i skieruj na widok, dla którego chcesz uzyskać adres URL”. Cóż, nie ma dla mnie radości :( Próbowałem wszystkich możliwych kombinacji i uciekłem się do publikowania tutaj w ostateczności.

Więc oto jest. Mój adres urls.py wygląda następująco:

from django.conf.urls.defaults import *
from login.views import *
from mainapp.views import *
import settings

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Example:
    # (r'^weclaim/', include('weclaim.foo.urls')),
    (r'^login/', login_view),
    (r'^logout/', logout_view),
    ('^$', main_view),

    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
    # to INSTALLED_APPS to enable admin documentation:
    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),
    #(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': '/home/arthur/Software/django/weclaim/templates/static'}),
    (r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT}),
)

Mój „views.py” w moim katalogu „login” wygląda następująco:

from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.contrib import auth

def login_view(request):
    if request.method == 'POST':
        uname = request.POST.get('username', '')
        psword = request.POST.get('password', '')
        user = auth.authenticate(username=uname, password=psword)
        # if the user logs in and is active
        if user is not None and user.is_active:
            auth.login(request, user)
            return render_to_response('main/main.html', {}, context_instance=RequestContext(request))
            #return redirect(main_view)
        else:
            return render_to_response('loginpage.html', {'box_width': '402', 'login_failed': '1',}, context_instance=RequestContext(request))
    else:
        return render_to_response('loginpage.html', {'box_width': '400',}, context_instance=RequestContext(request))

def logout_view(request):
    auth.logout(request)
    return render_to_response('loginpage.html', {'box_width': '402', 'logged_out': '1',}, context_instance=RequestContext(request))

i na końcu main.html, do którego wygląda punkt login_view:

<html>
<body>
test! <a href="{% url logout_view %}">logout</a>
</body>
</html>

Dlaczego więc za każdym razem otrzymuję „NoReverseMatch”?

* (nieco inaczej musiałem użyć „context_instance = RequestContext (request)” na końcu wszystkich moich renderowań do odpowiedzi, ponieważ w przeciwnym razie nie rozpoznałbym {{MEDIA_URL}} w moich szablonach i nie mogłem się odwołać żadnych plików css lub js. Nie wiem, dlaczego tak jest. Nie wydaje mi się to właściwe) *

Robert Johnstone
źródło
1
To, o czym mówisz, context_instance=RequestContext(request)jest poprawne, jest to konieczne, aby umożliwić szablonowi dostęp do zmiennych kontekstowych dostarczonych do wszystkich szablonów. Odbywa się to domyślnie dla wszystkich widoków ogólnych, ale w niestandardowych widokach musisz to zrobić samodzielnie.
Marcus Whybrow
Wydaje mi się to trochę dziwne, ponieważ będziesz mieć dostęp do swoich plików css i js przez cały czas ze swoich szablonów, aby zachować spójność w całej witrynie. Czy zatem nie powinieneś mieć domyślnie dostępu do adresu {{MEDIA_URL}}?
Robert Johnstone,
1
Przyjęta tutaj odpowiedź jest już nieaktualna
Dan Gayle
Dodaj nową odpowiedź, a potem ją zaakceptuję
Robert Johnstone,

Odpowiedzi:

55

Zamiast importować logout_viewfunkcję, powinieneś podać ciąg w swoim urls.pypliku:

Zatem nie (r'^login/', login_view),

ale (r'^login/', 'login.views.login_view'),

To jest standardowy sposób robienia rzeczy. Następnie możesz uzyskać dostęp do adresu URL w swoich szablonach za pomocą:

{% url login.views.login_view %}
Marcus Whybrow
źródło
2
tak, zdecydowanie użyj ciągów. w ten sposób możesz także używać prefiksów i nie musisz importować wszystkich funkcji widoku do swojego URLConf.
Sri Raghavan
Próbowałem tego również i otrzymałem komunikat „Caught NoReverseMatch podczas renderowania: Reverse for„ login.views.login_views ”z argumentami„ () ”i słowami kluczowymi„ {} ”not found.” znowu :(
Robert Johnstone,
Czekaj ... Podrap to! Czekałem 15 minut, spróbowałem ponownie i zadziałało (yippeeee !!!). Ładnie 1. Następne pytanie. Jeśli mam tylko jedną witrynę, którą dodałem na stronie administratora, jak mogę dodać sufiks do {% url ??? %}
Robert Johnstone
Tak, to nekro, ale tag URL nadal mnie gryzie w 2015 roku. Pomogłoby, gdyby nie zmieniali składni:
Dave
6
Tylko dlatego, że przyszedłem tu z Google, powinienem powiedzieć, że jeśli chodzi o django 1.8+, przekazywanie ciągów znaków jako argument widoku jest przestarzałe i wkrótce zostanie usunięte. Właściwie powinieneś przekazać wywołanie jak w tym poście.
user3599803
104

Wybrana odpowiedź jest nieaktualna i żadna inna nie działała dla mnie (Django 1.6 i [najwyraźniej] brak zarejestrowanej przestrzeni nazw).

Dla Django 1.5 i nowszych (z dokumentacji )

Ostrzeżenie Nie zapomnij umieścić cudzysłowu wokół ścieżki funkcji lub nazwy wzorca!

Dzięki nazwanemu adresowi URL możesz:

(r'^login/', login_view, name='login'),
...
<a href="{% url 'login' %}">logout</a>

Równie łatwe, jeśli widok przyjmuje inny parametr

def login(request, extra_param):
...
<a href="{% url 'login' 'some_string_containing_relevant_data' %}">login</a>
Mike S.
źródło
1
tak, wiem. {% load url from future %}W tej chwili używam wersji 1.4. Dobre miejsce
Robert Johnstone
5
To powinno zostać wybrane jako odpowiedź. Używanie ciągów znaków do odwrotnego dopasowywania adresów URL jest przestarzałe w nowszych wersjach django.
Sumudu,
44

Upewnij się (django 1.5 i nowsze), że umieściłeś nazwę adresu URL w cudzysłowie, a jeśli twój adres URL przyjmuje parametry, powinny one znajdować się poza cudzysłowami (spędziłem godziny na zastanawianiu się nad tym błędem!).

{% url 'namespace:view_name' arg1=value1 arg2=value2 as the_url %}
<a href="{{ the_url }}"> link_name </a>
Bogatyr
źródło
Wiem, że to stara odpowiedź, ale to naprawdę mi pomogło. Używam django-norel, który jest rozwidleniem Django 1.6, który również musi cierpieć na ten problem, ponieważ umieszczenie nazwy adresu URL w cudzysłowie naprawiło błąd TypeError, który otrzymywałem.
robobrobro
2
Korzystanie z właściwej dokumentacji również pomaga, ponieważ ciągle zmieniają składnię: {% url app_views.client client.id %}(bez cudzysłowów) w 1.4, {% url 'app_views.client' client.id %}(z cudzysłowami) w 1.5-1.7 i {% url 'app-views-client' client.id %}(bez podkreślenia i kropek, tylko myślniki) w 1.8.
Dave
O Boże i planowałem wkrótce uaktualnienie do wersji 1.8.
Bogatyr
17

urlSzablon minie parametr jako ciąg znaków, a nie jako odniesienie do funkcji reverse(). Najprostszym sposobem, aby to działało, jest dodanie namedo widoku:

url(r'^/logout/' , logout_view, name='logout_view')
Bernhard Vallant
źródło
Próbowałem, ale otrzymałem `` nieprawidłową składnię (urls.py, wiersz 14) '' :(
Robert Johnstone,
naprawdę dziwne w tym jest to, że (PyCharm - fajna aplikacja) nie pozwala mi używać> name = 'logout_view' <jak wyżej bez polecania importu biblioteki (libxml2mod.name lub unicodedata.name lub twisted.trial.runner. imię)
Robert Johnstone
Gdzie jest reverse()zdefiniowana funkcja ?
CodyBugstein
W szablonie za pomocą {% url 'logout_view'%} django.readthedocs.org/en/latest/intro/tutorial03.html
Juan Rojas
12

Mam ten sam problem.

To, co znalazłem z dokumentacji, powinniśmy użyć namedspace.

w Twoim przypadku {% url login:login_view %}

Alist
źródło
Korzystanie z przestrzeni nazw jest teraz znacznie częstsze. Sprawia, że ​​adresy URL są bardziej czytelne i faktycznie coś dla Ciebie znaczą
Robert Johnstone
Czy możesz dołączyć link do dokumentacji?
geoidesic
1

Sądząc po twoim przykładzie, czy nie powinno to być {% url myproject.login.views.login_view %}i koniec historii? (zastąp myprojectrzeczywistą nazwą projektu)

Yuji „Tomita” Tomita
źródło
To samo, co powyżej „Caught NoReverseMatch podczas renderowania: Odwróć dla„ weclaim.login.views.login_views ”z argumentami„ () ”i argumentami słów kluczowych„ {} ”nie znaleziono.” (Przypuszczam, że nazwa mojego projektu jest taka sama, jak nazwa katalogu głównego, w którym przechowywany jest cały mój kod)
Robert Johnstone