108

I have looked a lot on google for answers of how to use the 'url' tag in templates only to find many responses saying 'You just insert it into your template and point it at the view you want the url for'. Well no joy for me :( I have tried every permutation possible and have resorted to posting here as a last resort.

So here it is. My urls.py looks like this:

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

My 'views.py' in my 'login' directory looks like:

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

and finally the main.html to which the login_view points looks like:

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

So why do I get 'NoReverseMatch' every time?

(on a slightly different note I had to use 'context_instance=RequestContext(request)' at the end of all my render-to-response's because otherwise it would not recognise {{ MEDIA_URL }} in my templates and I couldn't reference any css or js files. I'm not to sure why this is. Doesn't seem right to me)

4
  • 1
    What you are saying about the context_instance=RequestContext(request) is correct, this is needed to allow the template access to the context variables provided to all templates. This is done by default for all generic views, but you need to do it yourself in your custom ones. Commented Jan 4, 2011 at 23:22
  • Seems a bit strange to me because you are going to be accessing your css and js files all the time from your templates to keep consistency across your site. Therefore shouldn't you be able to access {{ MEDIA_URL }} by default? Commented Jan 5, 2011 at 9:11
  • 1
    The accepted answer here is no longer valid Commented Feb 2, 2018 at 1:23
  • Add a new answer and then I'll accept that Commented Feb 22, 2018 at 16:28

7 Answers 7

124

The selected answer is out of date and no others worked for me (Django 1.6 and [apparantly] no registered namespace.)

For Django 1.5 and later (from the docs)

Warning Don’t forget to put quotes around the function path or pattern name!

With a named URL you could do:

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

Just as easy if the view takes another parameter

def login(request, extra_param):
...
<a href="{% url 'login' 'some_string_containing_relevant_data' %}">login</a>
Sign up to request clarification or add additional context in comments.

1 Comment

yeah I know. I'm using {% load url from future %} in 1.4 at the moment. Good spot
64

Instead of importing the logout_view function, you should provide a string in your urls.py file:

So not (r'^login/', login_view),

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

That is the standard way of doing things. Then you can access the URL in your templates using:

{% url login.views.login_view %}

5 Comments

yeah, definitely use strings. this way, you can also use prefixes, and you don't have to import all of your view functions into your URLConf.
I tried this as well and got 'Caught NoReverseMatch while rendering: Reverse for 'login.views.login_views' with arguments '()' and keyword arguments '{}' not found.' again :(
Wait... Scratch that! I waited 15 mins, tried it again and it worked (yippeeee!!!). Nice 1. Next question. If I only have one site that I have added in the admin page, how can I suffix this to {% url ??? %}
Yes this is a necro, but the URL tag is still biting me in 2015. It would help if they didn't keep changing syntax:
Just because I came here from google, I should say that as for django 1.8+, passing strings as view argument is deprecated, and will be soon removed. You should actually pass the callable like in this post.
52

Make sure (django 1.5 and beyond) that you put the url name in quotes, and if your url takes parameters they should be outside of the quotes (I spent hours figuring out this mistake!).

{% url 'namespace:view_name' arg1=value1 arg2=value2 as the_url %}
<a href="{{ the_url }}"> link_name </a>

3 Comments

I know this is an old answer, but this really helped me. I'm using django-norel, which is a fork of Django 1.6, which must also suffer this problem because encapsulating the url name in quotes fixed the TypeError I was getting.
Using the correct documentation helps too, since they keep changing the syntax: {% url app_views.client client.id %} (no quotes) in 1.4, {% url 'app_views.client' client.id %} (with quotes) in 1.5 -1.7, and {% url 'app-views-client' client.id %} (no underscores or dots, just dashes) in 1.8.
Oh Lord and I was planning to upgrade to 1.8 soon.
18

The url template tag will pass the parameter as a string and not as a function reference to reverse(). The simplest way to get this working is adding a name to the view:

url(r'^/logout/' , logout_view, name='logout_view')

4 Comments

I tried that but I got 'invalid syntax (urls.py, line 14)' :(
what's really weird about this is that it (PyCharm - nice app) won't let me use >name='logout_view'< as above with out recommending a library import (libxml2mod.name or unicodedata.name or twisted.trial.runner.name)
Where is the function reverse() defined?
In your template using {% url 'logout_view' %} django.readthedocs.org/en/latest/intro/tutorial03.html
13

From the documentation, we should use namedspace.

In your case, {% url login:login_view %}

2 Comments

Using namespaces a lot more now-a-days. Makes URL more readable and they actually mean something to you
Can you include the documentation link please?
1

For example, there are 4 views in my_app1/views.py as shown below. *You can see the doc explaining URL namespaces in detail:

# "my_app1/views.py"

from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return render(request, 'index.html')

def test1(request):
    return HttpResponse("Test1")

def test2(request):
    return HttpResponse("Test2")

def test3(request):
    return HttpResponse("Test3")

And, there are 2 paths in my_app1/urls.py as shown below:

# "my_app1/urls.py"

from django.urls import path
from . import views

app_name = "my_app1"

urlpatterns = [
    path('test1/', views.test1, name="test1"),
    path('test2/', views.test2, name="test2"),
]

And, there are 4 paths in core/urls.py as shown below:

# "core/urls.py"

from django.contrib import admin
from django.urls import path, include
from my_app1 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index),
    path('my_app1/', include('my_app1.urls')),
    path('test3/', views.test3, name='test3'),
]

Now, you can set these URL namespaces to url tag in index.html as shown below:

{% "index.html" %}

<a href="{% url 'admin:index' %}">Admin</a>
<a href="{% url 'my_app1:test1' %}">Test1</a>
<a href="{% url 'my_app1:test2' %}">Test2</a>
<a href="{% url 'test3' %}">Test3</a>

Comments

0

Judging from your example, shouldn't it be {% url myproject.login.views.login_view %} and end of story? (replace myproject with your actual project name)

1 Comment

Same as the above 'Caught NoReverseMatch while rendering: Reverse for 'weclaim.login.views.login_views' with arguments '()' and keyword arguments '{}' not found.' (I'm presuming that my project name is the same name as the root directory all my code is stored in)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.