Problem with Django reverse() - django

I am missing something really basic here.
I am trying to reuse django's change password views. I have following in urls.py:
(r'^change-password/$', 'profile.views.change_password', {},'change_password'),
url(r'^change-password-done/$', 'profile.views.password_change_done', name='django.contrib.auth.views.password_change_done'),
and in corresponding views.py:
from django.contrib.auth.views import password_change, password_change_done
def change_password(request,template_name="password_change_form.html"):
"""Change Password"""
return password_change(request,template_name=template_name)
def password_change_done(request, template_name="password_change_done.html"):
return render_to_response(template_name,(),context_instance= RequestContext(request))
but I am getting following error:
Reverse for
'django.contrib.auth.views.password_change_done'
with arguments '()' and keyword
arguments '{}' not found.
looked at the source and saw this line:
post_change_redirect = reverse('django.contrib.auth.views.password_change_done')
If I change my urls.py entry to following , I do not get the above error:
url(r'^change-password-done/$', 'django.contrib.auth.views.password_change_done', name='anything'),
but I am confused as reverse() should look-up using the "name" parameter? What am I missing here?
I am using django 1.2.3

Josh has the explanation, but you are doing this wrong. If you want to overrride the post_save_redirect, then pass that in as a parameter when you call the view:
def change_password(request,template_name="password_change_form.html"):
return password_change(request, template_name=template_name,
post_save_redirect=reverse('my_done_page'))
See the documentation.

The reverse function doesn't just do lookups on name.
Reverse Documentation.
reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
viewname is either the function name (either a function reference, or the string version of the name, if you used that form in urlpatterns) or the URL pattern name.
So, by doing reverse('django.contrib.auth.views.password_change_done'), it will look up that view name within the urls.py regexes, and fallback to looking for the name keyword argument if the viewname doesn't resolve.

Related

what is the differences between reverse and reverse_lazey methods in Django?

I can't use reverse() method in a class to generate url
for example, reverse() doesn't work in generic views or Feed classes (reverse_lazy() should be used instead)
but I can use reverse() in functions. what is the differences ?
take a look at following:
class LatestPostFeed(Feed):
title = 'My Django blog'
# link = reverse_lazy('blog:index')
description = 'New posts of my blog'
def items(self):
return models.Post.published.all()[:5]
def item_title(self, item):
return item.title
def item_description(self, item):
return truncatewords(item.body, 30)
def link(self):
return reverse('blog:index')
the link attribute above only works with reverse_lazy() method.
but the link function works with both reverse_lazy() and reverse() methods
reverse returns string and It's similar to the url template tag which use to convert namespaced url to real url pattern.
reverse_lazy returns object and It's a reverse() function’s lazy version. It’s prevent to occur error when URLConf is not loaded. Generally we use this function in case below:
providing a reversed URL as the url attribute of a generic class-based view.
providing a reversed URL to a decorator (such as the login_url argument for the django.contrib.auth.decorators.permission_required() decorator)
providing a reversed URL as a default value for a parameter in a function’s signature.

Django: passing value to template from DetailView context not working

I see the following error when trying to render my item_detail template, which uses a url tag in a link to the item_update view:
NoReverseMatch at /mcadb/27/items/17
Reverse for 'item_update' with arguments '()' and keyword arguments '{u'course_id': '', u'pk': 17}' not found. 1 pattern(s) tried: [u'mcadb/(?P<course_id>[0-9]+)/items/(?P<pk>[0-9]+)/update/$']
What is the problem trying to match the pattern tried? Is it because of the u? I'm not sure why that is happening.
In views.py, I try to add 'course_id' to the context for the DetailView. I try to get 'course_id' from the kwargs for the view (I don't know why it's blank)
views.py
class ItemDetailView(DetailView):
DetailView.model=Item
template_name='mcadb/item_detail.html'
def get_context_data(self, **kwargs):
context = super(ItemDetailView, self).get_context_data(**kwargs)
context['course_id'] = self.kwargs['course_id']
return context
urls.py
url(r'^(?P<course_id>[0-9]+)/items/(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='item_detail'),
url(r'^(?P<course_id>[0-9]+)/items/(?P<pk>[0-9]+)/update/$', views.ItemUpdate.as_view(), name='item_update'),
item_detail.html
Edit Item
The problem is with the 'course_id=course_id' line. If I change it to 'course_id=26', item_detail.html renders fine.
I have two questions.
1. what does the error mean, when it looks like I'm passing two kwargs as expected?
2. why does it work if I hardcode a course_id?
Thank you very much, Carrie
I think this is the error:
url(r'^(?P<course_id>[0-9]+)/items/(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='item_detail'),
Note that you are use a generic DetailView (from django.views.generic.DetailView) with this url.
You need to use your own View myapp.views.ItemDetailView.
So in your urls.py file:
from myapp.views import ItemDetailView
url(r'^(?P<course_id>[0-9]+)/items/(?P<pk>[0-9]+)/$', ItemDetailView.as_view(), name='item_detail'),
Explanation for your exact error is here:
Reverse for 'item_update' with arguments '()' and keyword arguments '{u'course_id': '', u'pk': 17}' not found. 1 pattern(s) tried: [u'mcadb/(?P[0-9]+)/items/(?P[0-9]+)/update/$']
As you can see, reverse is getting empty course_id and URL can't be built with empty, because there must be at least 1 number (+ sign in regex pattern). so there is definetly something wrong with passing course_id into context or into url tag. Try to print that variable next to url tag and check it's value. Check if you can access this variable somewhere else in your template (maybe outside of all for loops, includes and with tags) and if you can access it directly from your view (try to create URL here using reverse or just print variable to logs).

django url dispatcher with HTTP GET arguments

In a urls.py file:
url(r'^api/user_info/(?P<username>[a-zA-Z\d]+)\&', 'corresponding.view')
url(r'^api/user_info/(?P<username>[a-zA-Z\d]+)', 'corresponding.view')
There will always be HTTP Get arguments to /api/user_info/username.
The problem is that in the corresponding.view function, username will evaluate to something like "myusername?clientversion=2.0", instead of it evaluating to "myusername" and request.GET['clientversion'] = "2.0".
The first url call is to try to catch the ampersand in there, but it doesn't help.
Thanks in advance.
See this question; you don't access query parameters using Django's URLConf. Trying to process ? or & characters using the URL resolver will not lead to happiness.
Just use the following URL pattern:
url(r'^api/user_info/(?P<username>\w\+)/$', 'corresponding.view')
and access the clientversion query parameter in your corresponding.view() function:
def view(request):
client_version = request.GET.get('clientversion')
...
Or, if you're saying it should be mandatory,
from django.http import Http404
def view(request):
try:
client_version = request.GET['clientversion']
except KeyError:
raise Http404

passing url matching parameter to reverse() in urls.py

in my urls.py I need to invoke a generic CreateView that requires a success_url parameter. The "success" URL contains an identifier that I need to pass to the reverse() URL search function. I get this parameter from the URL of the CreateView. please see the code below. I need to grab the value of the <pk> parameter in the "create" url, and pass it on to the "success" url. how is this done?
thanks
konstantin
PS: using django trunk
...
url(r'^path/(?P<pk>\d+)/apply/$',
generic.CreateView.as_view(form_class=MyForm,
success_url=reverse_lazy('success', args=[???<pk>???]),
template_name='create.html'), name='create'),
url(r'path/(?P<pk>\d+)/apply/success/$',
generic.TemplateView.as_view(template_name='success.html'), name='success'),
...
This is explained in the documentation:
success_url may contain dictionary string formatting, which will be interpolated against the object's field attributes. For example, you could usesuccess_url="/polls/%(slug)s/" to redirect to a URL composed out of the slug field on a model.

Reverse for url generic views

This subject is continuation of thinking in this topic. I fell back in problem of reverse in generic views. Last time I thought it's no reverse match because I used many to many, now I haven't many to *** relations in reverse but problem still in there. Since I have generic view in urls in both cases, I suggested the problem is in generic views and no view function.
At first I used #permalink decorator in the models
...
#permalink
def get_absolute_url(self):
return ('categories', str(self.id))
...
#permalink
def get_absolute_url(self):
return ('pages', (), {'page_name': self.human_readable_url})
urls
url(r'^(?P<page_name>&\w*)?/?$', direct_to_template,
{'template': 'basic.djhtml'},
name = "pages"),
url(r'cat/\d+/$',
direct_to_template,
{'template': 'basic.djhtml'},
name = "categories")
And got an error:
NoReverseMatch: Reverse for 'pages' with arguments '()' and keyword arguments '{'page_name': u'page1'}' not found.
Then I tried reverse method
def get_absolute_url(self):
return reverse('categories', args = [self.id, ])
And have the same error
NoReverseMatch: Reverse for 'categories' with arguments '(2,)' and keyword arguments '{}' not found.
Based on the fact that permalink not explicitly use reverse method, I think that the problem is in interaction reverse and generic view in url. Why is it happens? How to use reverse in url generic views?
The problem is, you have given the name categories to a generic view, direct_to_template, and you are passing an argument to that view - but direct_to_template doesn't take that argument, only a dictionary containing extra context.
If you want to pass additional arguments to a generic view, you can - but they will only be passed on to the Template. You can extend the view by writing your own function, which adds the parameter into a dictionary, then calls the generic view. Something like this:
# views.py
from django.views.generic.simple import direct_to_template
def my_view(id):
more_data = {'id': id}
return direct_to_template(template = 'basic.djhtml', more_data)
And then in your urls.py, replace the direct_to_template with my_view. Since my_view takes an id argument, reverse will properly match it, and the argument will be passed in to the generic view, and through to the template.
Presumably somewhere in your template is a line such as, {{ id }}.