Double check e-mail validation at the Django backend - python

Considering that a user can disable JavaScript in the browser, how can I proceed with a "double check" for e-mail validation in the Django backend (specifically, to prevent register using Webmail [GMail, Hotmail and so on])? Thanks.

You can do it inside your forms.py(you have to create that file) app like this
from django import forms
class ContactForm(forms.Form):
full_name = forms.CharField()
email = forms.EmailField()
def clean_email(self, *args, **kwargs):
email = self.cleaned_data.get('email')
if email.endswith('#gmail.com'): # etc.
raise forms.ValidationError('This is not a valid email')
return email
Here you can find more about it

Related

How to change the field name of Serialzed User Model on frontend in Django Rest Framework?

I am making a simple Login/Logout App using REST API in Django DRF. I am using the default User model for this behavior.
In the Login API, I wanted to authenticate the user with email, hence I wrote the custom authentication using ModelBackend. Everything works fine.
But, I want to change the word username to email in the front of the Login API. I tried using the source attribute, but it does not change. Is there any easy way to do it? I am looking for something like verbose_name, that is used in Django Models.
My serializers.py is:
class LoginSerializer(serializers.Serializer):
username = serializers.CharField(source='Email')
password = serializers.CharField()
def validate(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError('Incorrect Credentials Passed.')
Again, I am using the default User Model, and I don't want to overwrite/override/extend the User Model. I just want to change the name of the field username on the frontend to be shown as email.
You need to pass a value called email and not username to your ModelBackend subclass:
class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
user = authenticate(**{'email': data['username'], 'password': data['password']})
if user and user.is_active:
return user
raise serializers.ValidationError('Incorrect Credentials Passed.')

How to change Django Authentication View "PasswordResetView" to send resent link to mobile number and email?

I have a Custom User Model and Custom Backend for authenticating via both mobile number and email.
I want to give my users the ability to reset the password via both email and mobile number, i.e., on the PasswordResetView I want to have both options for resetting the password with the reset password link sent on the mobile number and on the email.
I have my Django project configured to send messages with Twilio.
My question is how to change the PasswordResetView to be able to do that.
We need to override the form_class of the view PasswordResetView.
####### Your views.py #######
class PasswordResetViewOverride(auth_views.PasswordResetView):
form_class = PasswordResetFormOverride
And then to achieve the authentication custom logic we need to override the save method of this default form_class that the PasswordResetView had, i.e., PasswordResetForm. This class has a save method we need to override that. Moreover, we can write its custom clean method and add any other field, in this case, a mobile number field.
After grabbing the user with the field of mobile number we can generate the token for them as shown here. With this token, we will create a link and send to users' mobile number using any messaging client(like Twilio).
class PasswordResetFormOverride(PasswordResetForm):
mobile_no = forms.CharField(
label="Your Accounts' Mobile Number",
max_length=10,
widget=forms.NumberInput(),
required=False,
)
def save(self, domain_override=None,
subject_template_name='registration/password_reset_subject.txt',
email_template_name='registration/password_reset_email.html',
use_https=False, token_generator=default_token_generator,
from_email=None, request=None, html_email_template_name=None,
extra_email_context=None):
mobile_no = self.cleaned_data.get("mobile_no", "")
# All the previous stuff
if mobile_no != "":
# Send reset link to mobile logic
# All the previous stuff

Adding a new field along with username and password in django's login form

I want to edit the login form provided by django and don't want to build a new one because of the security issues. I have looked at other solutions like How to use another field for logging in with Django Allauth? it's a good example but it assigns email id based on mobile number. However I want to add another field that isn't particularly to authenticate just for input based on which redirection is done. I am quite confused about my approach and whether or not it is possible to do so. Kindly suggest. Thanks.
You can do that in your forms.py file by doing this.
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'}))
yourfield = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'yourfield'}))
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
#user_qs = User.objects.filter(username=username)
#if user_qs.count() == 1:
# user = user_qs.first()
if username and password:
user = authenticate(username=username, password=password)
if not user:
raise forms.ValidationError("This user does not exist")
if not user.check_password(password):
raise forms.ValidationError("Incorrect password")
if not user.is_active:
raise forms.ValidationError("This user is no longer active")
return super(UserLoginForm, self).clean(*args, **kwargs)
Apologies if I've misunderstood your question, but here is how I've added extra fields to user registration it which seems pretty straightforward. I've included some extra related methods just to be verbose:
../forms.py:
class CustomRegistrationForm(RegistrationForm):
"""
Form for registering a new user account.
Subclasses should feel free to add any additional validation they
need, but should avoid defining a ``save()`` method -- the actual
saving of collected user data is delegated to the active
registration backend.
"""
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label="Username",
error_messages={'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
email = forms.EmailField(label="E-mail")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
extra_field = forms.CharField([field options])
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The two password fields didn't match.")
return self.cleaned_data
Then, simply set your register URL to use the proper form class:
../urls.py:
url(r'^accounts/register/$', RegistrationView.as_view(form_class=accounts.forms.CustomRegistrationForm), name='registration_register'),
Is this field not part of your standard model, or does your input need to do some extra work? You can set a signal to make some extra magic happen when the user is registered:
from forms import CustomRegistrationForm
def user_created(sender, user, request, **kwargs):
form = CustomRegistrationForm(request.POST)
user_account = get_user_account(user)
user_account.persona = form.data['persona_tier']
user_account.save()
from registration.signals import user_registered
user_registered.connect(user_created)
FYI I'm using django-registration-redux backend but this approach should help get you close regardless.

IntegrityError column email is not unique [duplicate]

I am working on my Checkout view with regular/guest user but getting hard time to come around the integrity error. Idea is to let guest users register with email only to checkout and I need to set the user email unique.
models.py
from django.conf import settings
from django.db import models
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True)
email = models.EmailField(unique=True)
def __unicode__(self):
return self.email
forms.py
from django import forms
from django.contrib.auth import get_user_model
User=get_user_model()
class GuestCheckoutForm(forms.Form):
email = forms.EmailField()
email2 = forms.EmailField(label='Verify Email')
def clean_email2(self):
email = self.cleaned_data.get("email")
email2 = self.cleaned_data.get("email2")
if email == email2:
user_exists = User.objects.filter(email=email).count()
if user_exists != 0:
raise forms.ValidationError("User already exists. Please login instead")
return email2
else:
raise forms.ValidationError("Please confirm emails addresses are the same.")
In my cart views this is how I've rendered my form.
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
email = form.cleaned_data.get("email")
user_checkout = UserCheckout.objects.create(email=email)
return self.form_valid(form)
else:
return self.form_invalid(form)
I've registered the model with admin and in admin it shows the error for duplication perfectly fine but from frontend I am getting error below:
IntegrityError at /checkout/
column email is not unique
Request Method: POST
Request URL: http://localhost:8000/checkout/
Django Version: 1.8.13
Exception Type: IntegrityError
Exception Value:
column email is not unique
Exception Location: C:\Users\Ali\ecomm\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 318
Python Executable: C:\Users\Ali\ecomm\Scripts\python.EXE
Python Version: 2.7.9
You create every time when a checkout occurs an new UserCheckout. And in all these entries it is only allowed that every email exists only once.
I don't think you want this. Because if a guest orders two times it isn't allowed because his email is already in the DB. And that's why you get this error.
The clean_<fieldname> methods of a Form are used to perform validation relative to single field. If you need validation with access to multiple fields, use the clean method. Check the documentation on form validation for a thorough explanation.
That would give:
class GuestCheckoutForm(forms.Form):
email = forms.EmailField()
email2 = forms.EmailField(label='Verify Email')
def clean_email(self):
email = self.cleaned_data["email"]
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Please confirm emails addresses are the same.")
return email
def clean(self):
cleaned_data = super(GuestCheckoutForm, self).clean()
email = cleaned_data.get('email')
email2 = cleaned_data.get('email2')
if email and email2 and email != email2:
self.add_error('email2', forms.ValidationError('Please confirm emails addresses are the same.'))
EDIT: I believe I found out why you got an IntegrityError:
You are validation that no User with the given email is in the database, you should also be validating that no other UserCheckout with the given email is in the database. Replace if User.objects.filter(email=email).exists(): by if User.objects.filter(email=email).exists() or UserCheckout.objects.filter(email=email).exists():

Django form subclass non-functional

Here is a custom registration form inheriting from [django-registration][1]. My extra form fields do not appear and field cleaning methods do not run, something which I observe from the functionality and supported by the print statements (the Custom form runs print statement runs but not 'Custom Password clean'. Both the field appears and the validations run when placed into the original django-registration code, provided below.
Why is this happening?
my app/forms.py
from registration.forms import RegistrationForm
class CustomRegistrationForm(RegistrationForm):
"""
Form for registering a new user account.
Validates that the requested username is not already in use, and
requires the password to be entered twice to catch typos.
I have has added email uniqueness validation and minimum
password length validation.
Subclasses should feel free to add any additional validation they
need, but should avoid defining a ``save()`` method -- the actual
saving of collected user data is delegated to the active
registration backend.
"""
print 'Custom form runs'
LOCALITIES = (
('1', 'London'),
('2', 'Berlin'),
)
locality = forms.MultipleChoiceField(choices=LOCALITIES,
label='Where are you?',
widget=forms.CheckboxSelectMultiple)
def clean_password1(self):
"""
Verify that password is longer than 5 characters.
"""
print 'Custom Password clean'
password = self.cleaned_data['password1']
print 'custom valid'
if len(password) < 6:
raise forms.ValidationError(_("Password needs to be at least 6 characters long"))
return password
def clean_email(self):
"""
Validate that the supplied email address is unique for the site.
"""
email = self.cleaned_data['email']
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(_("This email address is already in use. \
Please supply a different email address."))
return email
django-registration
registration/forms.py
"""
Forms and validation code for user registration.
Note that all of these forms assume Django's bundle default ``User``
model; since it's not possible for a form to anticipate in advance the
needs of custom user models, you will need to write your own forms if
you're using a custom model.
"""
from django.contrib.auth.models import User
from django import forms
from django.utils.translation import ugettext_lazy as _
class RegistrationForm(forms.Form):
"""
Form for registering a new user account.
Validates that the requested username is not already in use, and
requires the password to be entered twice to catch typos.
Subclasses should feel free to add any additional validation they
need, but should avoid defining a ``save()`` method -- the actual
saving of collected user data is delegated to the active
registration backend.
"""
required_css_class = 'required'
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label=_("Username"),
error_messages={'invalid': _("This value may contain only letters, numbers and #/./+/-/_ characters.")})
email = forms.EmailField(label=_("E-mail"))
password1 = forms.CharField(widget=forms.PasswordInput,
label=_("Password"))
password2 = forms.CharField(widget=forms.PasswordInput,
label=_("Password (again)"))
def clean_username(self):
"""
Validate that the username is alphanumeric and is not already
in use.
"""
existing = User.objects.filter(username__iexact=self.cleaned_data['username'])
if existing.exists():
raise forms.ValidationError(_("A user with that username already exists."))
else:
return self.cleaned_data['username']
def clean_email(self):
"""
Validate that the supplied email address is unique for the site.
"""
email = self.cleaned_data['email']
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(_("This email address is already in use. \
Please supply a different email address."))
return email
def clean(self):
"""
Verify that the values entered into the two password fields
match. Note that an error here will end up in
``non_field_errors()`` because it doesn't apply to a single
field.
"""
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields didn't match."))
return self.cleaned_data
That's not how you customise a class based view. The third parameter in a urlconf is for parameters that are passed as part of the request, alongside those captured from the URL itself: it's not for configuring the class view.
To do that, you should either override the class in your code and set the attributes there, or you can pass them as parameters to the class's as_view() method:
url(r'^register/$', RegistrationView.as_view(form_class=CustomRegistrationForm, backend=registration.backends.default.DefaultBackend), name='registration_register'),

Categories