Timothy Joseph Baney Timothy Joseph Baney - 3 months ago 27
Python Question

Django request.user becomes anonymous after redirect

In my Django app I create a User from django.contrib.auth.models, and I am using request.user in multiple view functions without a problem. In one of my view functions I change the user password, save the user, and redirect the client to another view function. Once I try to get the user from the request in that function, the user is Anonymous. After using User.set_password() or redirecting, does it take the user out of the session ?

views.py

from django.contrib import messages
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render
from .models import Profile
from .forms import ProfileForm, PasswordForm


def sign_in(request):
form = AuthenticationForm()
if request.method == 'POST':
form = AuthenticationForm(data=request.POST)
if form.is_valid():
if form.user_cache is not None:
user = form.user_cache
if user.is_active:
login(request, user)
return HttpResponseRedirect(
reverse('home') # TODO: go to profile
)
else:
messages.error(
request,
"That user account has been disabled."
)
else:
messages.error(
request,
"Username or password is incorrect."
)
return render(request, 'accounts/sign_in.html', {'form': form})


def sign_up(request):
form = UserCreationForm()
if request.method == 'POST':
form = UserCreationForm(data=request.POST)
if form.is_valid():
form.save()
user = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1']
)
new_profile = Profile.objects.create(user=user)
login(request, user)
messages.success(
request,
"You're now a user! You've been signed in, too."
)
return HttpResponseRedirect(reverse('home')) # TODO: go to profile
return render(request, 'accounts/sign_up.html', {'form': form})


def sign_out(request):
logout(request)
messages.success(request, "You've been signed out. Come back soon!")
return HttpResponseRedirect(reverse('home'))

def profile(request):
user = request.user
try:
account = Profile.objects.get(user=user)
except Profile.DoesNotExist:
account = None

print(account.first_name)
context = {'account': account}

return render(request, 'accounts/profile.html', context)

def edit(request):
account = Profile.objects.get(user=request.user)
form = ProfileForm(instance=account)

if request.method == 'POST':
account = Profile.objects.get(user=request.user)

form = ProfileForm(request.POST, request.FILES)

if form.is_valid():
account.first_name = form.cleaned_data['first_name']
account.last_name = form.cleaned_data['last_name']
account.email = form.cleaned_data['email']
account.bio = form.cleaned_data['bio']
account.avatar = form.cleaned_data['avatar']
account.year_of_birth = form.cleaned_data['year_of_birth']
account.save()

context = {'account': account}

return HttpResponseRedirect('/accounts/profile')
else:
x =form.errors
context = {'form': form, 'errors': form.errors}

return render(request, 'accounts/edit.html', context)

else:

context = {'form': form}

return render(request, 'accounts/edit.html', context)

def change_password(request):
user = request.user

if request.method == 'POST':
form = PasswordForm(request.POST)

if form.is_valid():
cleaned_data = form.cleaned_data

if not user.check_password(cleaned_data['old_password']):
form.add_error('old_password', 'Old password is incorrect')

context = {'form': form}

return render(request, 'accounts/password.html', context)

try:
user.set_password(cleaned_data['new_password'])
user.save()

return HttpResponseRedirect('/accounts/profile')
except Exception as e:
form = PasswordForm()

context = {'form': form}

return render(request, 'accounts/password.html', context)

else:
form = PasswordForm()

context = {'form': form}

return render(request, 'accounts/password.html', context)


forms.py

class PasswordForm(forms.Form):
old_password = forms.CharField(max_length=200)
new_password = forms.CharField(max_length=200)
confirm_password = forms.CharField(max_length=200)

def clean(self, *args, **kwargs):
cleaned_data = super(PasswordForm, self).clean()

if 'new_password' in cleaned_data:
new_password = cleaned_data['new_password']
else:
new_password = None

if 'confirm_password' in cleaned_data:
confirm_password = cleaned_data['confirm_password']
else:
confirm_password = None

if confirm_password and new_password:
if new_password != confirm_password:
self.add_error('confirm_password', 'Passwords do not match')

Answer

Yes. See the documentation about session invalidation on password change. To fix it, see this bit in particular:

The default password change views included with Django, PasswordChangeView and the user_change_password view in the django.contrib.auth admin, update the session with the new password hash so that a user changing their own password won't log themselves out. If you have a custom password change view and wish to have similar behavior, use the update_session_auth_hash() function.