How to make Django form Field Unique? - django

I have a Signup form Where I want to make data of email and mobile Number Field to be Unique....
class SignUpForm(UserCreationForm):
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.', unique=True)
mobile_no = forms.CharField(validators=[max_length=17, initial='+91', unique=True)
I am Currently using unique=True but it raise Error as...
TypeError: __init__() got an unexpected keyword argument 'unique'

Easiest and fastest way(both for you and server) is to implement it in your model by setting unique=True.
If you want it in form anyway you need to override clean
Cleaning email:
class SignUpForm(UserCreationForm):
...
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise ValidationError("Email already exists")
return email
Now form.is_valid() will throw error if an user account with given email already exists.
I think you can figure out how to do same thing for mobile number now.

Related

Why django does not validate email in CustomUser model?

I had the following custom user model:
class CustomUser(AbstractUser):
"""User model."""
username = None
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
I was under the impression that I would at least get some errors if I tried to create a CustomUser with an invalid email. However, I have the following line it my unit tests:
CustomUser.objects.create_user(email='dave') # creates user!
Shouldn't the above make django throw an error, since 'dave' is clearly not an email? I know I can write a validator, but shouldn't there be already no need to do so?
Here's the UserManager:
class UserManager(BaseUserManager):
"""Define a model manager for User model with no username field."""
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_user(self, email, password=None, **extra_fields):
"""Create and save a regular User with the given email and password."""
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
Update: CustomUser(email='dave').clean_fields(), however, will throw the following error as expected: (but I am still curious what's up with my original question)
ValidationError: {'password': ['This field cannot be blank.'], 'email': ['Enter a valid email address.']}
Django does not run validators automatically outside of ModelForm's.
So when you do this:
CustomUser.objects.create_user(email='dave') # creates user!
The EmailField's validators (i.e. EmailValidator) will not be run. An error will only be thrown if the database has an issue with the value you are trying to assign. In this case it won't, because under the hood an EmailField is identical to a CharField and you're passing it a string ('dave').
How validators are run (Django docs):
Note that validators will not be run automatically when you save a model, but if you are using a ModelForm, it will run your validators on any fields that are included in your form.
I can understand the confusion. Your intuition is telling you that something defined in the models will be enforced by the ORM regardless of how it's represented in the database. The reality is that a lot of the Model field options are only used in forms (blank, choices, editable, help_text etc.).
From the source, the class AbstractUser doesn't define a validator for the emailfield, but one for username.
So if you want a validation from the model's field, you have to do it yourself.
(and overwritte the username if you want to change it)

Creating a login page for custom Django users? [duplicate]

I want to create a SINGLE form which gives the ability to the admin to create a new user with extended profile. Please note that, I don't want to use admin and registration apps.
I have extended the user with the UserProfile model. I have read all the documents related to extending user profile. But, I really don't know how to save these information.
I coded the following django form for this issue:
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField()
last_name = forms.CharField()
password1=forms.CharField(max_length=30,widget=forms.PasswordInput()) #render_value=False
password2=forms.CharField(max_length=30,widget=forms.PasswordInput())
email=forms.EmailField(required=False)
title = forms.ChoiceField(choices=TITLE_CHOICES)
def clean_username(self): # check if username dos not exist before
try:
User.objects.get(username=self.cleaned_data['username']) #get user from user model
except User.DoesNotExist :
return self.cleaned_data['username']
raise forms.ValidationError("this user exist already")
def clean(self): # check if password 1 and password2 match each other
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
raise forms.ValidationError("passwords dont match each other")
return self.cleaned_data
def save(self): # create new user
new_user=User.objects.create_user(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'],
)
return new_user
Is it OK? however it gives me an error in first_name and last_name. Says django doesn't expect first_name and last_name in save() method.
create_user only supports the username, email and password arguments. First call create_user, then add the extra values to the saved object.
new_user=User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()

Changing user's email address

I am building simple form which allows user to change his basic (first and last name, email) data.
I want to be sure that:
emails still unique across database
user can leave his email untouched
user can change his email
I wanted to use ModelForm for this. I've finished with something like:
class UserDataForm(ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
def clean_email(self):
cd = self.cleaned_data
email = cd['email']
# Not sure how to check is there is an other account which uses this email EXCEPT this particular user account
I need to show validation error message when there is another account which uses same email AND this account isn't owned by user who is filling the form.
I don't know how to achieve this.
Try this:
class UserDataForm(ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
def clean_email(self):
cd = self.cleaned_data
email = cd['email']
# object is exists and email is not modified, so don't start validation flow
if self.instance.pk is not None and self.instance.email == email:
return cd
# check email is unique or not
if User.objects.filter(email=value).exists():
raise forms.ValidationError("Email address {} already exists!".format(value))
return cd
Look at this question, I think it will be helpful.
Another way try to check email in clean method:
def clean(self):
cleaned_data = self.cleaned_data
if 'email' in self.changed_data and User.objects.filter(email=value).exists():
raise forms.ValidationError("Email address {} already exists!".format(value))
return cleaned_data

Django admin: Unique email verification fails against self

Hi Here's a snippet from my admin.py
#admin.py
class UserForm(forms.ModelForm):
class Meta:
model = User
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError("This email already used")
return email
class UserAdmin(admin.ModelAdmin):
form = UserForm
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
I use this to check that a new user cannot be created with an email address already used. The problem is that when I edit an existing user the validation check fails, because there is a user with that mail address, but that's OK because it's the one I'm editing.
How can I tell the form validation to ignore the match against the current user?
Exclude the current instance from your query:
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exclude(pk=self.instance.pk).exists():
raise forms.ValidationError("This email already used")
return email
It's much more better to validate uniqueness using unique on model field.
You can use custom User model with unique email constraint.
Look at this for more info about implementing unique validation on your own https://stackoverflow.com/a/1560617/527064

Creating an Add user form in Django

I want to create a SINGLE form which gives the ability to the admin to create a new user with extended profile. Please note that, I don't want to use admin and registration apps.
I have extended the user with the UserProfile model. I have read all the documents related to extending user profile. But, I really don't know how to save these information.
I coded the following django form for this issue:
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField()
last_name = forms.CharField()
password1=forms.CharField(max_length=30,widget=forms.PasswordInput()) #render_value=False
password2=forms.CharField(max_length=30,widget=forms.PasswordInput())
email=forms.EmailField(required=False)
title = forms.ChoiceField(choices=TITLE_CHOICES)
def clean_username(self): # check if username dos not exist before
try:
User.objects.get(username=self.cleaned_data['username']) #get user from user model
except User.DoesNotExist :
return self.cleaned_data['username']
raise forms.ValidationError("this user exist already")
def clean(self): # check if password 1 and password2 match each other
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
raise forms.ValidationError("passwords dont match each other")
return self.cleaned_data
def save(self): # create new user
new_user=User.objects.create_user(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'],
)
return new_user
Is it OK? however it gives me an error in first_name and last_name. Says django doesn't expect first_name and last_name in save() method.
create_user only supports the username, email and password arguments. First call create_user, then add the extra values to the saved object.
new_user=User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()