django 'url' template tag error - django

My URLconf contains this pattern:
url(r'^accounts/logout/$','django.contrib.auth.views.logout', name="logout"),
And I've trying to reverse that in a template with the URL tag like this:
logout
But I keep getting the following error:
Reverse for 'logout' with arguments '()' and keyword arguments '{'next_page': u'/first-page/child/'}' not found
I thought django.contrib.auth.views.logout is supposed to take an option next_page parameter. I'm sure I'm missing something obvious, but I'm not sure what it is.

Yes you're right, django.contrib.auth.views.logout does accept an optional "next_page" parameter, but don't forget that the "url" tag matches to urlconf patterns, not views, so it's not aware of what is or isn't a parameter of a view. So this suggests that you need to make "next_page" a named group in the regexp for the above pattern, which you could do, but there's an easier way to handle redirects...
Looking at django.contrib.auth.views.logout, you can see that in the absence of a "next_page" parameter, the view redirects to whatever url is provided in either request.GET or request.POST with the key "redirect_field_name", a parameter which defaults to "REDIRECT_FIELD_NAME" which in turn defaults to the string "next". So leaving your urlconf the way it is, you can do something like this in your template:
<a href='{% url logout %}?next={{ request.path }}'>logout</a>

Basically Django's URL dispatcher is looking at the urlconf and that argument and saying "I don't know where to put this argument" because it doesn't look at the view functions the urls point to, only the urlconf and the patterns in it.
Right now there's no place in your url pattern for that argument.
i.e. you can call django.contrib.auth.views.logout with the extra arguments if you write your own pattern for it or if you call it from your own view, but not from its default url pattern.
One of these url patterns might work for you (not tested):
url(r'^accounts/logout/(?P<next_page>.*)?$','django.contrib.auth.views.logout', name="logout"),
url(r'^accounts/logout/$','django.contrib.auth.views.logout', kwargs={'next_page':None}, name="logout"),
Hope that helps!

Related

Django how to define kwargs in a url pattern

url(r'^employee/create/(?P<employee_type>[\w-]+)$',
staff_member_required(EmployeeCreateView.as_view()),
name='employee-create'),
I am using the above url config for following url:
Create Product Engineer
Create Product Developer
But this gives me an error saying matching reverse url is not found. How may I fix this issue?
First you have to fix the url pattern, which is missing a slash, as pointed out by #Evert:
r'^employee/create/(?P<employee_type>[\w-]+)/$'
In your template you can call that url pattern as you have done it:
"{% url "myapp_app:employee-create" employee_type=product_eng %}"
Here it is important that myapp_app is the namespace, and employee-create the name of the url pattern.
From here we can't see whether you have this namespace specified.
For the part employee_type=product_eng is important that the variable product_eng actually exists in the template and holds a meaningful value.
You can simplify that by writing only:
"{% url "myapp_app:employee-create" product_eng %}"

identical views different URLs

I have following routs:
url(r'^future/programs/$', main.programs, {'period': 'future'}),
url(r'^past/programs/$', main.programs, {'period': 'past'}),
When I try to display link in template, using template tag url like this
{% url main.views.main.programs %}
I always get link /past/programs/. When I try like this
{% url main.views.main.programs period="future" %}
I get an error:
Caught NoReverseMatch while rendering: Reverse for
'main.views.main.programs' with arguments '()' and keyword arguments
'{'period': u'future'}' not found.
How i can display link to /future/programs/?
I think you might want to approach it with one single url pattern:
url(r'^(?P(<period>[\w]+)/programs/$', main.views.programs),
and in your view:
def programs(request, period):
if period == 'future':
...
elif period == 'past':
...
and in templates:
{% url main.views.main.programs period="future" %}
In your approach, you are mistaking the forward flow with the reverse flow, i.e. the extra keyword arguments of the url conf with the keyword arguments that are passed to match a pattern.
The former is extra data you are allowed to pass to a view when it is matched (i.e. when a user goes to /future/programs/, the pattern is matched and period=future is passed to the view), the latter is the actual data used to match the url (i.e. the period=future is passed to the reverse() function which tries to match a pattern that excepts those keyword arguments - which you haven't outlined)
Edit:
A more appropriate pattern to use in your url would be something like:
url(r'^(?P(<period>past|future)/programs/$', main.views.programs),
where the selection could only be 'past' or 'future'. This is fine for incoming urls, but django's reverse() function (which is used in the url template tag) can't handle alternative choices:
https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse
The main restriction at the moment is that the pattern cannot contain alternative choices using the vertical bar ("|") character.
I would rather assign each url a name:
url(r'^future/programs/$', main.programs,
{'period': 'future'},
name='future_programs'),
url(r'^past/programs/$', main.programs,
{'period': 'past'},
name='past_programs'),
And to display the link in your template:
Past programs: {% url past_programs %}
Future programs: {% url future_programs %}
I think this solution is better because if you just have two options for that view, you can forget about passing parameters and validating them.
Now, if those two options (future, past) can grow into several more, the other solution would be better, but I think this is not the case.

django pass extra option through url templatetag to view

I have the following line in my url file
url(r'^confirm/$', 'confirm', {'status':'live'}, name="confirm"),
As you can see I am passing the extra option status to the view which is described here
I would like to pass the status value through the template using the url templatetag. I tried
{% url confirm status='pending' %} but I get the following error:
Caught NoReverseMatch while rendering: Reverse for 'confirm' with arguments '()' and keyword arguments '{'status': u'pending'}' not found. Is it possible to do what I am trying to do?
How could this work? The url tag just outputs a URL that is valid in your urlconf and which maps the arguments into the URL. But your url has no place for alternative values for status - it's hard-coded.
If you want to pass parameters into a URL pattern, the pattern needs to have a space for the parameter.

How to debug Django NoReverseMatch errors?

Folks, I am getting a NoReverseMatch error for a particular url call.
I'd like to know: are there any good tools to debug these in general? For example, some way to list out which URLs are registered?
My particular example:
Template:
<a href=
"{% url django.contrib.auth.views.redirect_to_login blarg %}">log in</a>
Error:
NoReverseMatch: Reverse for
'settings.django.contrib.auth.views.redirect_to_login'
with arguments '('[[ UNDEFINED VARIABLE ]]',)'
and keyword arguments '{}' not found.
I am using Google App Engine with appenginepatch, so Django itself is modified.
In this particular case where the url reversal uses the full path to the view function, the easy thing to do is just go look at the view function. In Django-1.1 this looks like:
def redirect_to_login(next, login_url=None,
redirect_field_name=REDIRECT_FIELD_NAME):
"Redirects the user to the login page, passing the given 'next' page"
if not login_url:
login_url = settings.LOGIN_URL
return HttpResponseRedirect('%s?%s=%s' % (login_url,
urlquote(redirect_field_name),
urlquote(next)))
This function does not even take a request object, so its really not even a proper view, and it is not even registered in django/contrib/auth/urls.py. That means it's probably only meant to be used as a helper function in other views.
In any case, based on your particular example, what you probably wanted to do was use the plain old login url like so:
<a href="{% url django.contrib.auth.views.login %}?next={{request.path}}">
log in
</a>
Also, I believe if you set TEMPLATE_DEBUG = True in your settings, you will get a list of all the url patterns django checked against before throwing the error.

Can I reference a named URL in an included URLConf using Django's "url" tag?

In my Django project, I used to have a single URLConf, urls.py at the root of the project. This URLConf included some named URLs using Django's url() function. In several templates, I reference these URLs with the url tag, à la {% url named_url %}. This worked fine.
The root urls.py became a bit unwieldy, so I split it off into a URLConf for each app, in app/urls.py. Some URLs still have names. Unfortunately, I get a TemplateSyntaxException when using the url tag in templates now. Specifically, the error message is:
Caught an exception while rendering: Reverse for 'myproj.myapp.new_test' with arguments '()' and keyword arguments '{}' not found.
Is there a way to reference the named URLs in the app-specific URLConfs using the url tag in Django?
You definitely can reference urls in included urlconfs via the url tag - that's in fact what you're supposed to do. However, I've always found the url tag and the reverse() function to be very flaky and error-prone, so these errors do sometimes occur.
My suggestion would be to give all your urls a name, no matter which urlconf they are in. Then you just need to refer to the actual name - you don't need to qualify it with the name of the app or urlconf or anything. See if that works.
Are you referencing each app's urls.py?
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^app1/', include('app1.urls')),
(r'^app2/', include('app2.urls')),
)
from Django Docs
Probably not useful to you but hopefully useful to the next bloke searching for an answer:
I am using Django 1.4 and what solved it for me was not using quotes in the template tag:
{% url 'name_of_view' some_var %}
became this:
{% url name_of_view some_var %}
And that cured it. I didn't see any mention of this in the django docs and the examples in the docs use quotes. So this seems a little buggy but hopefully will keep someone from pulling out their hair.
https://docs.djangoproject.com/en/dev/topics/http/urls/#naming-url-patterns
I can recommend you two things:
Use name in url patterns
Do not do references to the project name inside a app(like you did with "myproj.myapp.new_test". If this was the "right way to do", you should only reference as "myapp.new_test"