Django redirect does nothing - python

I am currently try to redirect from one view to another view. However, nothing happens, the token gets printed and that's it.
class SocialLoginInvUserAPIView(APIView):
permission_classes = [AllowAny]
#staticmethod
def post(request):
print(request.data["token"])
return redirect("login/")
Here is the login url:
url(r'login/$',
LoginInvUserAPIView.as_view(),
name='auth_user_login'),

redirect("url_name")
This is how redirect works. Don't give url but give its name. Here,
you must write:
....
return redirect('auth_user_login')
....

Related

Unsafe redirect to URL with protocol django rest framework

When the user completes the registration process, I want to redirect her to the login page, where I get the following error.
Unsafe redirect to URL with protocol 'accounts'
What method should I use to solve this error?
class RegisterUser(APIView):
serializer_class = RegisterSerializer
def post(self, request):
serializer = self.serializer_class(data=request.POST)
serializer.is_valid(raise_exception=True)
serializer.save()
return HttpResponseRedirect('accounts:login')
Simply you can try this way:
Change this:
return HttpResponseRedirect('accounts:login')
To:
return HttpResponseRedirec('/accounts/login/')
Try and see if it solves the error
It should be either:
return redirect('accounts:login')
or:
return HttpResponseRedirect(reverse('accounts:login'))

Django: redirect url if slug is wrong

I have a function that is run every view to correct slugs.
For example if the slug is /12-post-about-stuff and a user enters /12-post-abot_stof they will be redirected correctly. The problem is that the different views have different url patterns for example:
/posts/post_slug/
...
/posts/post_slug/comments/new
how to I write a function that redirects by fixing the slug name based on the current url?
Edit: I am applying a decorator to every view with a board_name and pk argument. What I don't know is how to dynamically return the new url because the url format is different for each view.
def correct_board_url_name(func):
def wrapper(request, board_slug):
try:
pk = int(board_slug.split('-')[0])
board = Board.objects.get(pk=pk)
if (board.slug != board_slug):
# This does not always work depending on what is entered
return redirect(request.get_full_path().replace(board_slug, board.slug, 1))
else:
return func(request, board_slug)
except:
raise Http404('')
return wrapper
A middleware is a good choice if you want to process requests in many different views.
class RedirectMiddleware(object):
def process_request(self, request):
if request.resolver_match.app_name == 'posts' \
and 'post_slug' in request.resolver_match.kwargs:
new_path = None
# your logic here
if new_path:
return redirect(new_path, permanent=True)
return
In settings:
MIDDLEWARE = [
# another middlewares here ...
'path.to.RedirectMiddleware',
]

Redirecting Django built-in login View to a URL taking user's pk as argument

I am trying to redirect to a URL taking user's pk as argument after successful log-in using Django's built-in login view.
Instead of dynamic {{ next }} variable in my login.html I have a generic landing view of logged-in users;
<input type="submit" value="login" />
<input type="hidden" name="next" value="{% url 'userredirect' %}" />
In my urls.py I have;
url(r'^users/', views.users, name='userredirect'),
url(r'^(?P<pk>\d+)/', UserHome.as_view(), name='userhome'),
and in my views.py I have
#login_required
def users(request):
url = reverse('userhome', kwargs={'pk':request.user.id})
return HttpResponseRedirect(url)
What I am doing here is redirect to a detail view that I have named UserHome on the user model after successful login using 2 redirects as I do not know of a way to redirect to UserHome directly (it takes user's pk as argument). It works and I indeed get redirected to the user's homepage when checking via the browser.
Reference;
The "next" parameter, redirect, django.contrib.auth.login
But when running the below test
def test_page_redirects_to_user_home_on_login(self):
"""
Test to assure that the login page redirects to the user's
home page
"""
username = "someusername"
password = "somepassword"
user = User.objects.create_user(username=username,
password=password)
user.save()
response = self.client.post(reverse("userlogin"),
{"username":username,
"password":password},
follow=True)
assert response.path == self.client.get(reverse("userhome",
kwargs={"pk":user.id}
)
)
I get the below failure
AttributeError: 'HttpResponseNotFound' object has no attribute 'path'
It seems the test client gets no page. Would it be that I am using the userredirect view simply for redirecting and the client do not go ahead and get the UserHome class view to its context.
I'm a newbie to Django/Python. Someone please sort this out for me :).
I look forward either to a way where I can redirect directly from the template for login view to UserHome or a way to rewrite my test.
Hard to say without much more insight in your project. Here are a few possibilities and such.
Response has no path
response indeed has no path, you probably wanted this:
assert response.wsgi_request.path == reverse("userhome", kwargs={"pk":user.id})
Include next in your test
You're simulating data from the login form, but you're omitting the next field.
Add it to the POSTed data:
{"username":username,
"password":password,
"next": '/users/',}
Take a look what's in the response
It might help to see what's in the response in your test. For example:
print(response.redirect_chain)
Perhaps you're not even reaching the login page?
Are you missing LOGIN_URL in your settings.py?
LOGIN_URL = '/login/'
Without it, you'll be redirected to '/accounts/login/', which might be the 404 you're seeing.
Finaly - why? :)
Perhaps you have some special use case, but I'd usually read user's id (a.k.a. pk) from request.user. That way I (for example) can't access example.com/<your_id> and access your homepage. Of course, that might be just what you intend. In that case I'd still have a separate URL for current user, it will probably pay off later. Something like this:
...
url(r'^/', UserHome.as_view(), name='userhome'),
url(r'^(?P<pk>\d+)/', UserHome.as_view(), name='userhome'),
...)
class UserHome(DetailView): # also protect with some LoginRequiredMixin
model = User
def get_object(self, queryset=None):
if queryset is None:
queryset = self.get_queryset()
id = self.kwargs.get('pk', self.request.user.id)
return queryset.filter(id=id).get()
First things first: The error you get is because the line
response = self.client.post(reverse("userlogin"),
{"username":username,
"password":password},
follow=True)
raises a 404 error, hence resonse is a HttpResponseNotFound.
Before testing anything else is it a good practice to first test that your request was successful. Something along the line of:
self.assertEqual(response.status_code, 200)
Also, you are hard-coding url's which goes against DRY and is often the source for trouble (maybe it is the case here).
It would be better to name all your urls:
url(r'^users/', views.users, name='user_redirect'),
and then use this in your template
<input type="hidden" name="next" value="{% url 'user_redirect' %}" />
and this in your view
from django.core.urlresolvers import reverse
#login_required
def users(request):
url = reverse('userhome', kwargs={'pk': request.user.id})
return HttpResponseRedirect(url)
And finally, you are taking an unnecessary step with the redirect. Assuming UserHome is a DetailView on User, you could have this code:
##urls.py
url(r'^users/', UserHome.as_view(), name='userhome')
##views.py
from django.views.generic import DetailView
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
class UserHome(DetailView):
model = User
def get_object(self, queryset=None):
return self.request.user
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(UserHome, self).disatch(*args, **kwargs)
This would also ensure that no user accesses another user's "userhome".
Doing all this should help you find what went wrong with your code. Good luck!

Changing django-allauth render_authentication_error behavior

I'm a newcomer to the python/Django universe and just started a huge project I'm pretty excited about. I need to have my users login through Facebook and my app has a really specific user flow. I've set up django-allauth and everything works as I needed. I've overriden LOGIN_REDIRECT_URL so that my users land on the page I want when they log in.
BUT. When the user opens Facebook login dialog box and then closes it without logging in, the authentication_error.html template gets rendered by allauth.socialaccount.helpers.render_authentication_error, and this is not the behaviour I want. I want the user to simply be redirected to the login page.
Yes, I know I could simply override the template by putting it in my TEMPLATE_DIRS, but then the url wouldn't be the same.
I've come to the conclusion I needed a middleware to intercept the response to the http request.
from django.shortcuts import redirect
class Middleware():
"""
A middleware to override allauth user flow
"""
def __init__(self):
self.url_to_check = "/accounts/facebook/login/token/"
def process_response(self, request, response):
"""
In case of failed faceboook login
"""
if request.path == self.url_to_check and\
not request.user.is_authenticated():
return redirect('/')
return response
But I'm not sure about the efficiency of my solution nor the pythonesquitude (I juste came up with that word) of it. Is there anything else I could do to change that default django-allauth behavior without using a middleware or a signal?
Thanks!
Yes, I know I could simply override the template by putting it in my TEMPLATE_DIRS, but then the url wouldn't be the same.
Overriding a template won't change the URL. In your overridden template, you could do a client-side redirect to whatever URL you prefer.
I decided to use a middleware and redirect to home url in case a GET request is made on a URL of the form ^/accounts/.*$
from django.shortcuts import redirect
import re
class AllauthOverrideMiddleware():
"""
A middleware to implement a custom user flow
"""
def __init__(self):
# allauth urls
self.url_social = re.compile("^/accounts/.*$")
def process_request(self, request):
# WE CAN ONLY POST TO ALLAUTH URLS
if request.method == "GET" and\
self.url_social.match(request.path):
return redirect("/")

403 with django's class based view

So this is a simple view that I have written.
class PostTestView(View):
def post(self, request, *args, **kwargs):
print request.POST
return HttpResponse("Hello there")
my urls.py has this line for the above view :
url(r'^test/create$',PostTestView.as_view(), name='app.views.create_test')
But I get an 405 Http error when I try to hit http://127.0.0.1:8000/app/test/create
This apparently means that my method post is not in the defined methods list . But I have defined it as above in my view.
What could possibly be wrong here ? I am clueless
Try defining the get method.
The "post" method is commonly used in forms, but when you just point your browser to an url the used method is "get"

Categories

Resources