0

I don't know if its me but {% tag ??? %} has bee behaving a bit sporadically round me (django ver 1.2.3). I have the following main.html file:

<html>
{% include 'main/main_css.html' %}
<body>
test! <a href="{% url login.views.logout_view %}">logout</a>
test! <a href="{% url client.views.client_search_last_name_view %}">logout</a>
</body>
</html>

with the urls.py being:

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

# 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.views.login_view'),
    (r'^logout/$', 'login.views.logout_view'),
    (r'^$', 'mainapp.views.main_view'),

    (r'^client/search/last_name/(A-Za-z)/$', 'client.views.client_search_last_name_view'),
    #(r'^client/search/post_code/(A-Za-z)/$', 'client.views.client_search_last_name_view'),

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

and the views.py for login being:

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

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 redirect(mainapp.views.main_view)
        else:
            return render_to_response('loginpage.html', {'login_failed': '1',}, context_instance=RequestContext(request))
    else:
        return render_to_response('loginpage.html', {'dave': '1',}, context_instance=RequestContext(request))

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

and the views.py for clients being:

from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
import login.views

def client_search_last_name_view(request):
    if request.user.is_authenticated():
        return render_to_response('client/client_search_last_name.html', {}, context_instance=RequestContext(request))
    else:
        return redirect(login.views.login_view)

Yet when I login it django raises an 'NoReverseMatch' for {% url client.views.client_search_last_name_view %} but not for {% url login.views.logout_view %}

Now why would this be?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Robert Johnstone
  • 5,431
  • 12
  • 58
  • 88

3 Answers3

2

The "client.views.client_search_last_name_view" url's regex capatures a value (with the parens), so in order to {% url %} it, you need to pass it a value for that parameter.

Adam Vandenberg
  • 19,991
  • 9
  • 54
  • 56
  • no joy :( I still get >Caught NoReverseMatch while rendering: Reverse for 'client.views.client_search_last_name_view' with arguments '(1,)' and keyword arguments '{}' not found.< when I use >{% url client.views.client_search_last_name_view 1 %} – Robert Johnstone Jan 05 '11 at 16:58
  • Maybe double-check that "client" is in your INSTALLED_APPS? – Adam Vandenberg Jan 05 '11 at 17:23
  • @Sevenearths: If you have `(A-Za-z)` in your regex it will not work if you pass `1` as an argument, it need to be a letter... The url pattern will only match if also the arguments match the regular expressions! – Bernhard Vallant Jan 05 '11 at 17:30
  • Ah, right, what @lazerscience said; the value passed to URL needs to actually be capturable by the regex. – Adam Vandenberg Jan 05 '11 at 18:35
  • Adam Vandenberg: Good point. Figured that one out last night. – Robert Johnstone Jan 06 '11 at 08:17
  • Adam Vandenberg: In regards to the regex. I decide it is probably better coding practice to use a POST if it's searching clients – Robert Johnstone Jan 06 '11 at 08:18
  • "POST" is not a great choice for searching, as POST bypasses caching, and usually you want searches to use GET and be cached (for at least a little while) since users tend to run the same search more than once. – Adam Vandenberg Jan 06 '11 at 18:01
  • Adam Vandenberg: Not to worry. I intend to log all user interaction for the history. I doubt our office staff would want to perform the same search again, but I do know that they might like to revisit a client they view recently. But I get you point about GET and caching searches. – Robert Johnstone Jan 07 '11 at 08:36
1

AFAIK you want to add a name='foo' arg to each of your url regexes. That name is what is used in the reverse match. Like this:

urls.py

(r'^login/$', 'login.views.login_view', name="login"),

template.html

{% url login %}
JohnO
  • 1,889
  • 1
  • 12
  • 15
  • As you can see from my replay to lazyscience in (http://stackoverflow.com/questions/4599423/using-url-in-django-templates) PyCharm asks me to import various libraries to make it work. And it doesn't matter which one I import I always get an invalid syntax error. – Robert Johnstone Jan 06 '11 at 08:27
1

If you are creating a URL which is supposed to accept a last name the correct way would be as follows:

(r'^client/search/last_name/(?P<last_name>[a-zA-Z]+)/$',
    'client.views.client_search_last_name_view'),

The (?P<last_name>[a-zA-Z]+) part of the regex allows you to capture the last name which is at least one character in length and then have it passed as an argument to your view function.

However you then need to ensure that your view does accept this argument:

def client_search_last_name_view(request, last_name):
    ...

The reason you cannot then do:

{% url client.views.client_search_last_name_view %}

is because your regex states (like the view) that it needs one argument, which is a string consisting of lower or upper cases letters from A to Z. So for example this would work:

{% url client.views.client_search_last_name_view 'somelastname' %}

If you want to give your URL a name as another answer has suggested you can, but that is a separate matter and has no effect other than shortening that template tag.


The reason {% url login.views.logout_view %} does work is because its entry in urls.py does not specify any arguments to be passed to the view and, through default alone you have not passed any.

Marcus Whybrow
  • 19,578
  • 9
  • 70
  • 90
  • Hands up... You right! As you can see from the other comments I have decided to run with POST instead because I want to list all clients alphabetically. I don't suppose regex takes nothing like POST can? – Robert Johnstone Jan 06 '11 at 08:32
  • You shouldn't you POST, if you are suggesting that using POST makes it secure that is not the case. POST should only be used for submitting data to the server, not then displaying a search results page back to the user. GET request should be used for all pages which are viewable. – Marcus Whybrow Jan 06 '11 at 08:37
  • Your right again! I just started off on the wrong track when thinking about how best to do search submission (or submitting an text input for that matter) – Robert Johnstone Jan 06 '11 at 09:24