I'm new to django (1.5.1) and got a bit stuk with HttpResponseRedirect.
If I understand right that needs a static string, and when you want it to dynamic redirect, you get a reverse() or a get_absolute_url()
I think I get the part of the get_absolute_url, but I'm stuck on redirecting to the following url (first is mysite.urls.py second is my characters.view.py
url(r'^users/', include('characters.urls')),
url(r'^(?P<user_id>\d+)/characters/$', views.user_characters, name='user_characters'),
from this view:
if new_char_form.is_valid():
#save form with commit=False
new_char_obj = new_char_form.save(commit=False)
#set user and save
new_char_obj.user = user
new_char_obj.save()
return HttpResponseRedirect('%s/characters/' % user.id)
So I know I can't use the HttpResponseRedirect that way, and since I can't include a get_absolute_url function in the user model, I found the next option.
Include this in my settings
ABSOLUTE_URL_OVERRIDES = {
'auth.users': lambda o: "/users/%s/" % o.id,
}
but then I have no clue how to call for that.
Can someone please give me help (sort of stuck on this for some time)
With kind regards
Hans
The easiest way to redirect to the user_characters view is to use the redirect shortcut.
from django.shortcuts import redirect
# in the view
return redirect('user_characters', user.id)
This is equivalent to using HttpResponseRedirect and reverse
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
# in the view
return HttpResponseRedirect(reverse('user_characters', args=[user.id]))
If you want to use ABSOLUTE_URL_OVERRIDES to override the get_absolute_url method for the User model, you have to make sure that the url matches the format of your view named user_characters.
ABSOLUTE_URL_OVERRIDES = {
'auth.users': lambda o: "/users/%s/characters/" % o.id,
}
You would then be able to call user.get_absolute_url() in your views, and do
return HttpResponseRedirect(user.get_absolute_url())
Or, since the redirect shortcut allows you to pass a model instance:
return redirect(user)
Related
Hello! Please tell me how to organize a redirect correctly.
There is an old version of the site and a new one. In the old version (another CMS, not Django) the objects have their own URL, in the new revised scheme, and the objects have a different URL.
In each object on the new site, there is a completed field with the old URL. In model.py it looks like this:
old_url = models.CharField('Old URL', blank=True, max_length=100)
I specifically moved the old url to a separate field. Or was it not necessary to do this?
Question. How to set up a redirect correctly, so that after going to the object using the old URL, the site visitor will be redirected to the new URL of this object?
IMHO, I don't think writting old_url for each and every object is pretty inefficient. Instead you can implement a custom 404 view, and handle the redirection there.
I think you can create some regex or plain url maps to new url and redirect accordingly.
import re
from django.http import HttpResponseNotFound
OLD_URL_MAP = { 'old_url_regex': 'new_url_path'}
def handler404(self, request):
for old_re, new_url in OLD_URL_MAP.items():
if re.match(old_re, request.path):
return redirect(new_url, request.resolver_match.kwargs)
return HttpResponseNotFound('not found')
# inside urls.py
handler404 = 'myapp.views.handler404'
Here I have used a map hard coded in python, you can create a model for that as well.
Update
A costly solution is to use middleware. You can try like this:
import re
from django.urls import resolve
OLD_URL_MAP = { 'old_url_regex': 'new_url_path'}
class RerouteMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
try:
resolve(request.path_info) # trying to find if the current url exists in your django project. if not, it will throw exception.
except:
for old_re, new_url in OLD_URL_MAP.items(): # iterating through urls
if re.match(old_re, request.path):
return redirect(new_url, request.resolver_match.kwargs)
response = self.get_response(request)
return response
And add that middleware at the bottom of MIDDLEWARE settings.
FYI, its a regex based solution, assuming those urls are dynamic. Instead you can use plain text urls, but its up to you.
Use redirect() from django.shortcuts [the same library from where you import render]. Also, assuming, that the old_url contains only the relative url.
from django.shortcuts import render, redirect
def someView(request):
q = ~some queryset returning the current object~
current_url = request.get_full_path().strip("http://www.example.com/")
if q.old_url == current_url:
redirect(q.new_url)
else:
pass
Remember, redirect() returns an HttpResponse.
I'm pretty new to django and i'm working on a website that needs a dynamic URL for a database table, and it all works fine, but i would like to know how to remove the "?id=" from the url, so rather than
localhost:8000/dynamicurl/?id=XXXXX
The url becomes
localhost:8000/dynamicurl/XXXXX
Instead
I did a fine amount of searching in the documentation and didn't find a lot, though it's pretty likely i missed something.
EDIT:
thanks everyone for helping, the simplest answer was to remove the object i was using to fetch the ID and just replace it for ID in evert instance,
so my url became
url(r'^dynamicurl/(?P[0-9]+)/$', views.dynamicurl)
and my view became
def dynamicurl(request, id):
i'm like very very new to django FYI
you can capture a variable in url definition in the apps urls.py file. It would look something like this:
url(r'^dynamicurl/(?P<id>[0-9]+)?$', dynamicurl, name = 'dynamicurl'),
then in your view function you receive that parameter:
def dynamicurl(request, id):
If you are talking about how to change your url inside the urls, I suggest you to use code that already answered above: https://stackoverflow.com/a/41988051/6396981
But, if you talking about how to redirect localhost:8000/dynamicurl/?id=XXXXX to localhost:8000/dynamicurl/XXXXX, hope this usefull..
1. views.py
from django.http import HttpResponse
from django.views.generic.base import RedirectView
from django.core.urlresolvers import reverse
class RedirectView(RedirectView):
permanent = False
def get_redirect_url(self):
get_id = self.request.GET.get('id')
if get_id is not None:
return reverse('redirected_page', kwargs={'id': id})
return reverse('origin_page')
def redirected_view(request, id):
# your final view goes here...
return HttpResponse("You're looking for id: %d." % id)
2. urls.py
from django.conf.urls import url
from yourapp.views import views (RedirectView, redirected_view)
urlpatterns = [
# first view the pool to doing redirection
url(r'^pool/$', RedirectView.as_view(), name='origin_page'),
# the final url
url(r'^pool/(?P<id>[\d]+)/$', redirected_view, name='redirected_page'),
]
I am having a problem with HttpResponseRedirect in Django. It seems that, whatever parameters I try, it either throws an error, or it redirects without changing the URL. I am using it on a custom login_user view, and I want the URL in the address bar to change after they are redirected. If I use redirect instead of HttpResponseRedirect, it does not change. Either way, I can get it to serve the correct template, but the URL stays the same. Being new to Django, it would be helpful if someone could explain to me how to do this and why my current code is not working.
I have seen a couple of similar questions to mine on Stack Exchange, but the answers have not helped.
Here are the relevant parts of my views.py (please note the indenting has gone weird due to copying and pasting in here, and is not the cause of the error).
from django.http import *
from django.contrib.auth import authenticate, login, logout
def login_user(request):
logout(request)
username = password = ''
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('dashboard')
else:
state = "Your account is not active, please contact the app administrator."
else:
state = "Your username and/or password were incorrect."
state = "Please log in below..."
context = RequestContext(request, {
'state': state,
'username': username,
})
return render_to_response('bank/auth.html', {}, context)
dashboard is the name of another view, and it works fine in a redirect from my index view. I've also tried hard-coding the url in, but that doesn't work either. Any suggestions?? Thanks.
If you use HttpResponseRedirect, you must provide the url, not the name of the url.
You can either get the url by using reverse:
from django.core.urlresolvers import reverse
def my_view(request):
...
return HttpResponseRedirect(reverse('dashboard'))
or by using the redirect shortcut.
from django.shortcuts import redirect
def my_view(request):
...
return redirect('dashboard')
If using the either of the above approaches does not work, then there's probably a mistake somewhere else in the view. It's difficult to tell where, since the indentation is incorrect. Try adding some logging or print statements to see if you are really returning the redirect where you think you are.
In this particular case, the problem wasn't anything to do with my view code, it was actually a problem caused through using JQuery mobile. I found the answer here: Error with Redirects in JQuery Mobile which was to set the data-url attribute on the page div.
However, I have up-voted Alasdair's answer, as his way is the correct one of the ways I had tried.
I personally prefer the simple way as follows:
In urls.py:
url(r'^dashboard/$', 'appname.views.dashboard_view', name='dashboard_view'),
In views.py:
from django.http import HttpResponseRedirect
def dashboard_view(request):
...
return HttpResponseRedirect('/dashboard/')
Trying to limit my objects to 1 in admin pages. I get "newuserpath object with primary key u'add/foo' does not exist." It would be ok if it would just return without setting anything, but ideally with an error message. This is what I have in my admin.py.
from django.contrib import admin
from fileman.models import Newuserpath
from django.http import HttpResponseRedirect
class NewuserpathAdmin(admin.ModelAdmin):
def add_view(self, request):
if request.method == "POST":
# Assuming you want a single, global Newuserpath object
if Newuserpath.objects.count() > 0:
# redirect to a page saying
# you can't create more than one
return HttpResponseRedirect('foo')
return super(NewuserpathAdmin, self).add_view(request)
admin.site.register(Newuserpath, NewuserpathAdmin)
I'm following the best answer here: Is it possible to limit of object creation of a model in admin panel?
It just doesn't quite work.I tried using the other method by adding code in forms.py and importing it from there. But I'm unsure of how to use that in my admin.py.
The error is simply that you are using a relative path for your redirect - so the browser is adding 'foo' to the existing URL, admin/app/newuserpath/add/.
The best way to manage this is to use the URL reverse function - assuming you have given your error page URLconf the name 'newuserpath_error':
return HttpResponseRedirect(reverse('newuserpath_error'))
I've found very odd thing about using reverse in Django 1.2.1.
I have:
myapp/
views.py
urls.py
in urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('myapp.views',
url(r'^$', 'browse'),
)
in views.py
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse
print reverse('myapp.views.browse') # <----- this will print correct value
def browse (request):
print reverse('myapp.views.browse') # <----- this fails with exception
return render_to_response('myapp/browse.html')
When I put reverse method anywhere outside the view method (browse - in this case) I get an exception in every further use of reverse or {% url %} tag.
NoReverseMatch at /
Reverse for 'myapp.views.browse' with arguments '()'
and keyword arguments '{}' not found.
WTF? When I comment/delete the print line outside browse() , second print line inside browse() magically start working!
The most basic case is:
class MyForm(forms.Form):
field = forms.CharField(default=reverse(....))
def some_view(request):
print reverse(...)
....
1) I define a class in main-scope that is initialized when django initialize (and runs reverse)
2) When a request comes the some_view function has been triggered and it evaluates the reverse function again (and fails with exception).
I don't see anything bad at all in this approach. Why not to initialise some values in the django main-scope with results of the reverse() function ?
You will probably need to pass 'request' as the second parameter when calling reverse() from within the view function after it's already been called.
def browse(request):
print reverse('myapp.views.browse', args=[request])
This is odd behavior indeed, but this might possibly be a solution for now.
First, you should be naming your URLs in order to use reverse. That is the correct approach AFAIK.
Second, why are you calling reverse from within a FormField? I really don't get it.
Maybe you could enlighten us by posting the full code rather than a curated set of snippets.
# urls.py
url(r'^/$', 'home_view', name='home'),
url(r'^login/$', 'login_view', name='login'),
# views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
def login_view(request):
# do login stuff and redirect to home
return HttpResponseRedirect(reverse('home'))
def home(request):
# do home stuff
return render_to_response("home.html", locals(), context_instance=RequestContext(request))
The problem is caused by import hell in python. reverse depends on other things and cannot be used while initialization.
The solution is to use lazy reverse. E.g. using this:
http://djangosnippets.org/snippets/499/