I'm trying to get a local copy of a Django site working. The production site works just fine on login, but my local instance doesn't redirect to the profile page after completing the login form.
This is the login_page view:
def login_page(request):
profile_page = HttpResponseRedirect('profile')
if request.user.is_authenticated():
return profile_page
form = LoginForm(request.POST or None)
if request.POST and form.is_valid():
user = form.login(request)
if user:
login(request, user)
return profile_page
return render(request, 'login.html', {'form': form})
This is what the debug output of the server shows:
Performing system checks...
<function home_page at 0x7f77ad696c08>
System check identified no issues (0 silenced).
July 08, 2017 - 03:21:39
Django version 1.9.1, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[08/Jul/2017 03:21:49] "GET / HTTP/1.1" 200 3276
[08/Jul/2017 03:21:50] "GET /login HTTP/1.1" 200 2370
[08/Jul/2017 03:21:57] "POST /login HTTP/1.1" 302 0
[08/Jul/2017 03:21:57] "GET /profile HTTP/1.1" 302 0
[08/Jul/2017 03:21:57] "GET /login?next=/profile HTTP/1.1" 200 2370
After the above, the browser is left at http://127.0.0.1:8000/login?next=/profile and just displays the standard login page.
Again, identical code is working on the same version of Django in production (though running through gunicorn/nginx instead of django-admin runserver), so it makes me think that there's something in my Django config that I'm missing rather than an actual code problem.
urls.py entries:
from accounts import urls as account_urls
...
url(r'^', include(account_urls)),
accounts/urls.py:
from django.conf.urls import url
import accounts.views
urlpatterns = [
url(r'profile/?$', accounts.views.user_profile_page,
name='user_profile_page'),
Profile view (this never gets triggered AFICT - sticking a breakpoint in there doesn't help):
@login_required
def user_profile_page(request):
"""Returns user home page, with respective user status of surveys."""
print "User profile accessed: %s" % request
// user specific data here
context = {'some': some, 'data': data,
'here': here, }
return render(request, 'accounts/profile.html', context)
Also interesting: resolve_url doesn't seem to do the remapping like I would expect:
(Pdb) resolve_url('/profile')
'/profile'
Shouldn't that point to acccounts/profile or 127.0.0.1:8000/profile or something like that?
This is the AUTHENTICATION_BACKEND's 'authenticate' method that is getting executed (not sure how this differs from standard Django). All of the answers here imply that authenticate needs to accept the request argument - can I update this method to append something here?:
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
if username is not None:
username = username.lower()
user = UserModel._default_manager.get_by_natural_key(username)
if user.check_password(password):
return user
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
try this
from django.shorcuts import redirect
from django.contrib.auth import authenticate
def login_page(request):
profile_page = HttpResponseRedirect('profile')
if request.user.is_authenticated():
return profile_page
form = LoginForm(request.POST or None)
if request.POST and form.is_valid():
user = authenticate(request,username=form.cleaned_data['username'],password=form.cleaned_data['password'])
if user:
login(request, user)
return redirect('profile')
Instead of HttpResponseRedirect which triggers a HTTP 302, use a HttpResponseTemporaryRedirect to trigger a HTTP 307.
What happens is that 302 does not ensure the replay of the POST request. The reason is as follows:
RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client.
What's the difference between a 302 and a 307 redirect?
Changed in Django 1.10: In older versions, when you’re manually logging a user in, you must successfully authenticate the user with authenticate() before you call login(). Now you can set the backend using the new backend argument.
If you using Django<=1.10, you must use authenticate method before you login. Otherwise, you have to feed authentication backend at least in login method. Here is the code snippet from django docs.
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
Try modifying:
profile_page = HttpResponseRedirect('profile')
to:
profile_page = HttpResponseRedirect(reverse('profile'))
try with class bassed views
class Login(FormView, View):
template_name = 'login/login.html'
form_class = AuthenticationForm
success_url = reverse_lazy("your_succes:url")
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated():
return HttpResponseRedirect(self.get_success_url())
else:
return super(Login, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
login(self.request, form.get_user())
return super(Login, self).form_valid(form)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With