django default registration module takes unique username but same email - python

I am using the django default registration module to signup users.
What the module is doing, it is registering users with different username but same email.
How would I be able to send them forgot_password email if it is doing so ??
I wrote this in my views.py so that same email doesnt get registered but this is also not working. users are still getting registered with same email.
def register_user(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
try:
user_present = User.objects.get(username=form.username)
except:
user_present = None
if user_present:
messages.error(request, 'Username already taken')
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html',args)
else:
try:
user_present = User.objects.get(email=form.email)
except:
user_present = None
if user_present:
messages.error(request, 'Your email is already registered.')
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html',args)
else:
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
messages.error(request, 'There were errors in the form. Please fill again.')
return render_to_response('register.html',args)
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html',args)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
Is there any way to add unique=True like this ? :
email = forms.EmailField(required=True,unique=True)

As I understand you are using incorrect values for username and email. You should get them from form like this: form.cleaned_data['username'] and form.cleaned_data['email']. Also I suggest to put this validation into Form itself. Read about clean_fieldname methods here. One more thing: you don't need any uniqueness test for username cause it's by default defined as unique=True so just test for email:
class MyRegistrationForm(UserCreationForm):
# your code here
def clean_email(self):
email = self.cleaned_data.get('email')
if email:
if User.objects.filter(email=email).exists():
raise forms.ValidationError('Your email is not unique.')
return email
Your view now is gonna look much simpler without these uniqueness tests.

Related

The #login_required decoration is not working in Django (user not authenticated?)

I am trying to set up a login page and I am trying to use the #login_required decoration. However, whenever I try and log in with valid credentials I am re-directed to the 'login' page (set to re-direct unauthenticated users). I am not sure if the problem is in the #login_required decoration or perhaps the login() function is not authenticating the user.
Here is my code for the register form:
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'password']
code for login function in views.py:
def login_user(request):
if request.method =="GET":
return render(request, "main/login.html", {})
else:
username = escape(request.POST['userfield'])
password = escape(request.POST['passfield'])
try:
user = User.objects.get(username=username)
except:
user = None
if user is None:
try:
user = User.objects.get(email=username)
except:
user = None
if user is None:
messages.info(request, "*Sorry, that username or email does not exist")
return redirect('login')
pword = user.password
if check_password(password, pword):
login(request, user)
return redirect('homepage')
else:
messages.info(request, '*Sorry, that was an incorrect password')
return redirect('login')
my model for User in models.py:
class User(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
username = models.CharField(max_length=100)
email = models.EmailField(unique=True)
password = models.CharField(max_length=100)
admin = models.BooleanField(default=False)
last_login = models.DateTimeField(null=True, blank=True)
and my function to reach the 'homepage' after login:
#login_required(redirect_field_name='login')
def homepage(request):
return render(request, "main/homepage.html", {})
When you make custom user model, so you should always use AbstractBaseUser.
Note: It's also not a good practice to name same your models, django already has User model in the django.contrib.auth, so change its name.
So, you haven't specified the custom user model, so you should not able to authenticate, as by default authentication model is User which is at django.contrib.auth. So, with the current code when you make superuser through python manage.py createsuperuser and then you authenticate, so it will work.
You should use #login_required(login_url='login') instead of #login_required(redirect_field_name='login').
You need to correctly authenticate the user before logging in.
from django.contrib.auth import authenticate, login
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
More information in the documentation

How to login either through a mobile no or a email address in django?

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

Django User Authentication and Login with DRY

I am trying to create a simple login using Django authentication. All the code here is working but I am thinking that it is violating DRY principles. I will explain:
In my forms.py I have a simple login form:
class LoginForm(forms.Form):
email = forms.CharField()
password = forms.PasswordField()
def clean(self):
email = self.cleaned_data.get('email', None)
password = self.cleaned_data.get('password', None)
u = authenticate(email, password)
if u is None:
raise forms.ValidationError(ERROR_MSG)
if not u.is_active:
raise forms.ValidationError(ERROR_MSG)
so I am doing a check of User here already. However, in my views.py:
def login(request):
login_form = LoginForm(request or None)
if login_form.is_valid():
#This part is repeated
email = request.POST.get('email')
password = request.POST.get('password')
u = authenticate(email, password)
login(request, u)
return render(request, 'home.html', {})
I am querying the database again, which to me seems to violate DRY. Does anybody have a better way of doing this? I want to reuse the LoginForm for other uses, but also want to do it cleanly.
Any ideas?
Instead of doing the authenticate() twice, you can set the user on the form object and then use this user in your view.
forms.py
class LoginForm(forms.Form):
email = forms.CharField()
password = forms.PasswordField()
def clean(self):
email = self.cleaned_data.get('email', None)
password = self.cleaned_data.get('password', None)
self.u = authenticate(email, password) # set the user as an instance variable
if self.u is None:
raise forms.ValidationError(ERROR_MSG)
if not self.u.is_active:
raise forms.ValidationError(ERROR_MSG)
views.py
def login(request):
login_form = LoginForm(request or None)
if login_form.is_valid():
login(request, login_form.u) # directly pass the user by accessing from login_form object
return render(request, 'home.html', {})

Display django user creation form error

I'm using django built in user creation form which I extended like this
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'placeholder': 'E-mail address'}))
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'username', 'password1', 'password2')
def clean_email(self):
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
#raise forms.ValidationError(self.error_messages['duplicate_email'])
raise forms.ValidationError('duplicate_email')
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
As you see I've added email validation to check if there is already user with that email (what I don't accept).
The problem is that neither that of those errors are displaying in my template and I don't know why. I've tried with {{form.field.errors}} and even with {{form.errors.values.[i]}} but nothing helps
I looked in auth.forms to check class UserCreationForm and I see that it pass errors to error_messages but I couldn't find the way to display them.
Although all validations (username check, password check, email check) work fine I'd still like to display error above field with error so that user understands why he couldn't create his account.
UPDATE
views.py
def register_user(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
args = {}
args.update(csrf(request))
args['form'] = RegistrationForm()
return render_to_response('user_profile/register.html', args, context_instance=RequestContext(request))
I hope somebody can help me with that.
Thanks
This will work:
def register_user(request):
args = {}
args.update(csrf(request))
if request.method == 'POST':
form = RegistrationForm(request.POST)
args['form'] = form
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
args['form'] = RegistrationForm()
return render_to_response('user_profile/register.html', args, context_instance=RequestContext(request))
The problem with your code was that you was passing an unbound form instance to your template all the time, so you was just overwriting any occured errors.
Look here for a reference: docs
If you are looking at more efficient solution then you should try my below code in views.py file.
Your forms.py code will be same. But it is leakage of validation of password.
# to register auth user
class register_user(View):
template1 = "app_name/register.html" # define templates
template2 = "app_name/login.html"
def get(self, request): # get method
form = RegistrationForm()
return render(request, self.template1, locals())
def post(self, request): # post method
form = RegistrationForm(request.POST) # create form object
if form.is_valid():
print "Form is validated"
user_data = form.save(commit=False)
user_data.save()
return render(request, self.template2, locals())
else:
print "with error"
return render(request, self.template1, locals())
I hope this will help. I'm still working on good practice of Django.

Checking if username exists in Django

I am working on a Django project where users will be able to change their usernames along with their first and last name in one form. In forms.py, I am trying to find out if the user exists. If so, it should display an error.
The problem is that if user wants to change his first and last name and leaves his username in the input, it raises a validation error. Obviously, that username already exists.
Is there a way to check if it equals the username of currently logged user and avoid displaying the error?
class ChangeNameForm(forms.ModelForm):
username = forms.CharField(max_length=30)
first_name = forms.CharField(max_length=255)
last_name = forms.CharField(max_length=255)
def clean_username(self):
username = self.cleaned_data['username']
try:
user = User.objects.get(username=username)
except user.DoesNotExist:
return username
raise forms.ValidationError(u'Username "%s" is already in use.' % username)
When ModelForms are bound to a model object, they have an attribute called 'instance', which is the model object itself. In your view, when request.method == 'POST', you're probably creating the form instance like this:
form = ChangeNameForm(request.POST, instance=request.user)
If that's the case, you can access the logged user from the form methods, and your validation method can be something like this:
def clean_username(self):
username = self.cleaned_data['username']
try:
user = User.objects.exclude(pk=self.instance.pk).get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(u'Username "%s" is already in use.' % username)
Consider using the .exists method, for it issues a faster query to your database than if you try to retrieve all the user information with the .get method. And the code gets a little cleaner too:
def clean_username(self):
username = self.cleaned_data['username']
if User.objects.exclude(pk=self.instance.pk).filter(username=username).exists():
raise forms.ValidationError(u'Username "%s" is already in use.' % username)
return username
Optionally, you can also follow these guidelines when raising the ValidationError.
I can't test this code right now, so I apologize if there's anything wrong.
You can write function to check the username if exists like this:
#ggorlen, thanks! Update:
from django.contrib.auth.models import User
def username_exists(username):
return User.objects.filter(username=username).exists()
from django.contrib.auth.models import User
def username_exists(username):
if User.objects.filter(username=username).exists():
return True
return False
This is how I managed to make it work (assuming you have a logged in user):
forms.py
from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth.models import User
class MyUserChangeForm(UserChangeForm):
def __init__(self, *args, **kwargs):
super(MyUserChangeForm, self).__init__(*args, **kwargs)
del self.fields['password']
class Meta:
model = User
fields = ('username', 'first_name')
views.py
def home(request):
if request.method == 'POST':
form = MyUserChangeForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
else:
form = MyUserChangeForm(instance=request.user)
return render(request, 'change_user.html', {"form": form})

Categories

Resources