Im sure this was working and now it's not. Anyone know what could be up? its failing at the new_user = form.save(commit=False)
class Signup(View):
def get(self, request):
return render(request, 'accounts/signup.html')
def post(self, request):
form = UserCreationForm(request.POST)
new_user = form.save(commit=False)
email=new_user.cleaned_data.get('email')
new_user.username=email
if new_user.is_valid():
new_user.save()
username = new_user.cleaned_data.get('username')
raw_password = new_user.cleaned_data.get('password')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('/accounts/home/')
That line and the following two should be inside the if block; you can't save if the form is not valid.
Related
I have a Django app that already has a web interface for changing passwords. It uses django.contrib.auth functions and django.views.generic.UpdateView. Here is the code:
class PasswordChangeView(LoginRequiredMixin, generic.UpdateView):
form_class = PasswordChangeForm
template_name = 'form.html'
input_value = 'update password'
def post(self, request, *args, **kwargs):
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
try:
request.user.auth_token.delete() # Important!
except (AttributeError, ObjectDoesNotExist):
pass
messages.success(request, 'Your password was successfully updated!')
return redirect('/')
else:
messages.error(request, 'Please correct the error below.')
def get(self, request, **kwargs):
form = PasswordChangeForm(request.user)
return render(request, self.template_name, {'form': form, 'input_value': self.input_value})
The above code works fine in the web interface. Now I want to implement REST API for changing passwords. I know that I can create APIView/viewset and serializer to do that (like the answers for this question), but it will violate DRY principle. What is the best way to implement the REST API interface for that given that there is already a fully-functional web interface?
Implementing the Django rest framework for API and standard Django web views are a little bit different.
I suggest you create different endpoints for those.
I have encapsulated the common part of changing the password in a function called update_user_after_password_change so that it can be used in both view and viewset. Then I have ended up using the following code structure.
In views.py:
class PasswordChangeView(LoginRequiredMixin,
generic.UpdateView):
form_class = PasswordChangeForm
template_name = 'form.html'
input_value = 'update password'
def post(self, request, *args, **kwargs):
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_user_after_password_change(request, user)
messages.success(request, 'Your password was successfully updated!')
return redirect('/')
else:
messages.error(request, 'Please correct the error below.')
def get(self, request, **kwargs):
form = PasswordChangeForm(request.user)
return render(request, self.template_name, {'form': form, 'input_value': self.input_value})
class PasswordChangeViewSet(mixins.UpdateModelMixin,
viewsets.GenericViewSet):
permission_classes = [IsAuthenticated]
def get_object(self):
user = self.request.user
return user
def update(self, request, *args, **kwargs):
user = self.get_object()
serializer = serializers.PasswordChangeSerializer(data=request.data)
if serializer.is_valid():
old_password = serializer.data.get('old_password')
if not user.check_password(old_password):
return Response({'old_password': ['Wrong password.']},
status=status.HTTP_400_BAD_REQUEST)
user.set_password(serializer.data.get('new_password'))
user.save()
update_user_after_password_change(request, user)
return Response(status=status.HTTP_204_NO_CONTENT)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def update_user_after_password_change(request, user):
update_session_auth_hash(request, user)
if hasattr(user, 'auth_token'):
user.auth_token.delete()
In serializers.py:
class PasswordChangeSerializer(serializers.Serializer):
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
def validate_new_password(self, value):
validate_password(value)
return value
There might be a better way by using this but I do not know how to proceed with that.
Here's my forms.py,
class RegistrationForm(UserCreationForm):
class Meta:
model = User
fields = [ 'username', 'first_name', 'password1', 'password2']
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
if commit:
user.save()
return user
In views.py,
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
username = request.POST.get('username')
password = request.POST.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
return redirect(reverse('accounts:profile'))
else:
form = RegistrationForm()
return render(request, 'accounts/reg_form.html', {'form': form})
Right now if i'm using the same username it's raising an error which says "The view accounts.views.register didn't return an HttpResponse object. It returned None instead." How can I fix this issue?
Thank You :)
Django form by default does this for you.
You don't need specific for this.
Beacuse, default User Model provided by django doesn't take duplicate username.
May be some indentation problem
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
. . . .
else:
form = RegistrationForm()
return render(request, 'accounts/reg_form.html', {'form': form})
#^^^^^Indentation here take return statement outside else
I initially used to login using email and password but now want to change it in such a way that we can login using either mobile no or email address and password.I am not able to understand what parts to change in my code as I do not want to delete already existing user and data.
forms.py
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
views.py
class UserFormView(View):
form_class = UserForm
template_name = 'main/registration_form.html'
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
# cleaned (normalized) data
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user.username = email
user.set_password(password)
user.save()
# return user objects if credentials are correct
user = authenticate(username=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
# request.user.username display their username
return redirect('main:register2')
return render(request, self.template_name, {'form': form})
class LoginForm(View):
form_class = UserForm
template_name = 'main/login_form.html'
def get(self, request):
form = self.form_class(None)
if error:
return render(request, self.template_name, {'form': form},
{'error': error})
else:
return render(request, self.template_name, {'form': form})
def post(self, request):
email = request.POST.get('email', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=email, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect("/main/home/")
else:
# Show an error page
error = True
return HttpResponseRedirect("/main/", {'error': error})
Please answer considering the fact that I am new to Django. Thanks in advance :)
In the post method of your view, identify what has the user given you. If it's an email, feed the Django's authenticate() method with the email. If not, then assume it's a phone number (you may also run additional validations in there) and use this in the authentication procedure.
Another approach would be to create a custom authenticate() method, which would look like this:
from django.contrib.auth.backends import ModelBackend
class MobilePhoneOrEmailModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
# the username could be either one of the two
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'mobile_phone': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, username):
try:
return User.objects.get(pk=username)
except User.DoesNotExist:
return None
Let me know if this worked out well for you.
Credits to user user3282276 in this thread as well: Log in user using either email address or username in Django
I am learning class based views in Django 1.8, and wondering if anyone could help me here. I have created a function based login and logout views as you can see below:
LOGIN
def Login(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/form')
else:
return HttpResponse("Inactive user.")
else:
return HttpResponseRedirect(settings.LOGIN_URL)
return render(request, "index.html")
LOGOUT
def Logout(request):
logout(request)
return HttpResponseRedirect(settings.LOGIN_URL)
Could anyone help me to convert these views into Class Based Views in Django? I am pretty new to this stuff, and couldn't understand properly how exactly they are working. Will appreciate any help!
Go through the documentation https://docs.djangoproject.com/en/1.8/topics/class-based-views/intro/#using-class-based-views
from django.views.generic import View
class LoginView(View):
def post(self, request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/form')
else:
return HttpResponse("Inactive user.")
else:
return HttpResponseRedirect(settings.LOGIN_URL)
return render(request, "index.html")
class LogoutView(View):
def get(self, request):
logout(request)
return HttpResponseRedirect(settings.LOGIN_URL)
I have a login_page function and in this function the authenticate() function returns a user object only if it is a superuser. For normal user, it returns None. Which is not as the documentation says.
def login_page(request):
if request.user.is_authenticated(): # if user is already logged in
return HttpResponseRedirect('/') # SHOULD BE DASHBOARD
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
seo_specialist = authenticate(username=username, password=password) #returns None
if seo_specialist is not None:
login(request, seo_specialist)
return HttpResponseRedirect('/') # SHOULD BE DASHBOARD
else:
return render(request, 'login.html', {'form': form})
else:
return render(request, 'login.html', {'form': form})
else:
form = LoginForm()
context = {'form': form}
return render(request, 'login.html', context)
Is there anything wrong with my code?
Try this:
def login_page(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
seo_specialist = authenticate(username=username, password=password)
if seo_specialist is not None:
return HttpResponse("Signed in")
else:
return HttpResponse("Not signed in")
else:
# takes you to sign in form.
Basically replace is_valid and cleaned_data with request.POST and then authenticate. Also make sure you have
from django.contrib.auth import authenticate
at the top of your views.
This is from django documentation. You seem to not have passed the request in ...authenticate(request, user...)
This example shows how you might use both authenticate() and login():
from django.contrib.auth import authenticate, login
def my_view(request):
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.
...