Django HttpResponsePermanentRedirect don't process my view - django

If I put this in my view:
if slug == 'old-path':
return HttpResponsePermanentRedirect('new-path')
it skips my slugbased view and returns 404.
How do I easily return 301 and "reprocess" my view so I don't get a 404?
EDIT
#Pydev UAs comment was the correct answer in this case, but I appreciated the detailed answer by John Debs, which gave me the hint to look into named urls, which I didn't know about. Thanks all.

Add from django.core.urlresolvers import reverse to your list of imports and then try this bit of code:
if slug == 'old-path':
return HttpResponsePermanentRedirect(reverse('new-path'))
The problem you had was that HttpResponsePermanentRedirect() needs a path but you were providing it with a slug.
reverse() will search through your named URLs for the string you provide and return a path, which can then be redirected to properly.

Related

How to append string in the end of Django redirect in view?

I have a product on my platform and when a specific user does an action, I want to redirect them to example.com/product/product-slug/#SectionInWebsite.
However, I am not able to find a way to append "#SectionInWebsite" to the end of the redirect function.
return redirect('ProductSingle', product.slug, "#SectionInWebsite")
This worked for me (I had to use different names on my machine, but it should work):
# views.py
return redirect('{}#sectionInWebsite'.format(reverse('ProductSingle', kwargs={'product_slug':product.slug})))
That is, assuming your urls.py has something like this:
# urls.py
...
path('ProductSingle/<str:product_slug>', views.ProductSingle, name='ProductSingle'),
...
This is just a variation of the answer provided here, applied to your situation.
do this :
return redirect(reverse('ProductSingle',product.slug) + '#SectionInWebsite')
Maybe this can help you, using reverse.
return redirect(reverse('ProductSingle', product.slug) + '#SectionInWebsite')

Django NoReverseMatch at

I have the following URLs:
url(r'^%sdform/' %(URLPREFIX), pv.dform, name='dform'),
url(r'^%sform/(P?<growl>.*)/' %(URLPREFIX), pv.dform, name='dform'),
The view code:
def dform(request, growl = None) is the method signature
The redirect code:
msg = 'test'
return redirect('dform', growl=msg)
Any idea why I get that error? I'm sending the right parameter to the right view method with the right argument name and all that.
EDIT:
Based on the answer below, I tried:
url(r'^%sdform/(P?<growl>.*)/' %(URLPREFIX), pv.dform, name='dform_message')
And changed the redirect to:
return redirect('dform_message', growl='Updated Settings')
I still get NoReverseMatch
I think your problem is that you shall not use the same names for different urls (django docu).

Can I pass non-URL definition view keyword to a view function when redirecting?

NoReverseMatch at /natrium/script/4c55be7f74312bfd435e4f672e83f44374a046a6aa08729aad6b0b1ab84a8274/
Reverse for 'run_details' with arguments '()' and keyword arguments '{'script_text': u'print "happy"', 'run_id': '6b2f9127071968c099673254fb3efbaf'}' not found.
This is an excerpt of my views.py
run_id = new_run.run_id
if not run_id:
raise AssertionError("bad run id")
# I tried with args=[run_id, clean['script_text']] too
return HttpResponseRedirect(reverse('run_details', kwargs={'run_id':run_id, 'script_text':clean['script_text']}))
which in turns calling this view function
def run_details(request, run_id, script_text):
"""
Displays the details of a given run.
"""
run = Run(run_id)
run.update(request.user)
codebundle = CodeBundle(run.cbid)
codebundle.update(request.user)
return render_response(request, "graphyte/runs/run_script.html",
{'run':run, 'codebundle':codebundle, 'files':run.artifacts, 'bundle':codebundle,
'source_code': script_text
})
Now this is my urls.py. The actual redirect views is in another app (kinda insane, but whatever...).
urlpatterns = patterns("webclient.apps.codebundles.views",
# many.....
url(r"^cb/newfolder/$", 'codebundle_newfolder', name="codebundle_newfolder"),
)
urlpatterns += patterns('webclient.apps.runs.views',
url(r"^run_details/(?P<run_id>\w+)/$", 'run_details', name="run_details"),)
This is getting really nasty for the last three hours. I am not sure what's going on. Can someone help me debug this?
Thanks.
The original plan did not have script_text, and I used args=['run_id'] only. It works. In other words, remove script_text from the two views everything will work.
EDIT
Sorry for the confusion. Script text is just a context variable that I need to pass to the reverse destination, and from there I render my template. The URLs should only display the run_id.
No, you can't really pass an 'extra keyword' to the view function when redirecting. I'll try to explain why.
When you return HttpResponseRedirect, Django returns a response with a 302 status code, and the new location.
HTTP/1.1 302 Found
Location: http://www.example.com/new-url/
Your browser will then usually fetch the new url, but that's a separate request. If your view needs a keyword, it needs to be included in that response somehow, unless you store state in the session. Your two options are
Include the extra keyword in the url:
http://www.example.com/new-url/keyword-value/
Include the extra keyword as a GET parameter
http://www.example.com/new-url/?keyword=keyword-value.
Then in your view, grab the keyword with keyword=request.GET['keyword']. Note that the keyword is no longer a kwarg in the view signature.
A third approach is to stick the keyword into the session before you redirect, then grab it out the session in the redirected view. I would advise against doing this because it's stateful and can cause odd results when users refresh pages etc.
Your run_details url doesn't accept a kwarg named script_text at all -- remove that from your reverse kwargs.

Django URLConf Redirect with odd characters

I'm getting ready to move an old Classic ASP site to a new Django system. As part of the move we have to setup some of the old URLs to point to the new ones.
For example,
http://www.domainname.com/category.asp?categoryid=105 should 301 to http://www.domainname.com/some-category/
Perhaps I'm regex stupid or something, but for this example, I've included in my URLconf this:
(r'^asp/category\.asp\?categoryid=105$', redirect_to, {'url': '/some-category/'}),
My thinking is that I have to escape the . and the ? but for some reason when I go to test this, it does not redirect to /some-category/, it just 404s the URL as entered.
Am I doing it wrong? Is there a better way?
To elaborate on Daniel Roseman's answer, the query string is not part of the URL, so you'll probably want to write a view function that will grab the category from the query string and redirect appropriately. You can have a URL like:
(r'^category\.asp', category_redirect),
And a view function like:
def category_redirect(request):
if 'categoryid' not in request.GET:
raise Http404
cat_id = request.GET['category']
try:
cat = Category.objects.get(old_id=cat_id)
except Category.DoesNotExist:
raise Http404
else:
return HttpResponsePermanentRedirect('/%s/' % cat.slug)
(Altered to your own tastes and needs, of course.)
Everything after the ? is not part of the URL. It's part of the GET parameters.

Reverse Not Found: Sending Request Context in from templates

N.B This question has been significantly edited before the first answer was given.
Hi,
I'm fairly new to django, so apologies if I'm missing something obvious.
I've got a urls.py file that looks like this:
urlpatterns = patterns(
'',
(r'^$', 'faros.lantern.views.home_page'),
(r'^login/$', 'django.contrib.auth.views.login'),
(r'^logout/$', 'django.contrib.auth.views.logout'),
(r'^about/$', 'faros.lantern.views.about_page_index', {}, 'about_page_index'),
(r'^about/(?P<page_id>([a-z0-9]+/)?)$', 'faros.lantern.views.about_page', {}, 'about_page'),
)
Views that looks like this:
def about_page_index(request):
try:
return render_to_response('lantern/about/index.html', context_instance=RequestContext(request))
except TemplateDoesNotExist:
raise Http404
def about_page(request, page_id):
page_id = page_id.strip('/ ')
try:
return render_to_response('lantern/about/' + page_id + '.html', context_instance=RequestContext(request))
except TemplateDoesNotExist:
raise Http404
And a template that includes this:
Contact
Contact
I'm getting this error message:
Caught an exception while rendering: Reverse for '<function about_page at 0x015EE730>' with arguments '()' and keyword arguments '{'page_id': u'contact'}' not found. The first reverse works fine (about_page_index), generating the correct URL without error messages.
I think this is because the request argument to the about_page view (request) is used, so I need to pass it in when I generate the URL in my template. Problem is, I don't know how to get to it, and searching around isn't getting me anywhere. Any ideas?
Thanks,
Dom
p.s. As an aside, does that method of handling static "about" type pages in an app look horrific or reasonable? I'm essentially taking URLs and assuming the path to the template is whatever comes after the about/ bit. This means I can make the static pages look like part of the app, so the user can jump into the about section and then right back to where they came from. Comments/Feedback on whether this is djangoic or stupid appreciated!
If I guess correctly from the signature of your view function (def about_page(request, page_id = None):), you likely have another URL configuration that points to the same view but that does not take a page_id parameter. If so, the django reverse function will see only one of these, and it's probably seeing the one without the named page_id regex pattern. This is a pretty common gotcha with reverse! :-)
To get around this, assign a name to each of the url patterns (see Syntax of the urlpatterns variable). In the case of your example, you'd do:
(r'^about/(?P<page_id>([a-z]+/)?)$', 'faros.lantern.views.about_page',
{}, 'about_with_page_id')
and then in the template:
Contact
Edit
Thanks for posting the updated urls.py. In the url template tag, using the unqualified pattern name should do the trick (note that I'm deleting the lantern.views part:
Contact
Contact
Edit2
I'm sorry I didn't twig to this earlier. Your pattern is expressed in a way that django can't reverse, and this is what causes the mismatch. Instead of:
r'^about/(?P<page_id>([a-z]+/)?)$'
use:
r'^about/(?P<page_id>[a-z0-9]+)/$'
I created a dummy project on my system that matched yours, reproduced the error, and inserted this correction to success. If this doesn't solve your problem, I'm going to eat my hat! :-)