How to make email field unique in User model from contrib.auth in Django

I need to fix the standard contrib.auth user contrib.auth , making sure the email field entry is unique:

 User._meta.fields[4].unique = True 

Where is the best place in the code for this?

I want to avoid using numeric fields [4]. This is better for user fields ['email'], but fields are not a dictionary, but only a list.

Another idea is to open a new ticket and download the patch with a new parameter inside settings.py :

 AUTH_USER_EMAIL_UNIQUE = True 

Any suggestions on the best way to achieve unique email addresses in your Django user model?

+48
django django-models
Jul 21 '09 at 15:42
source share
17 answers

Surprisingly, I found the best solution for me!

django-registration have a form with checking the uniqueness of the email field: RegistrationFormUniqueEmail

usage example here

+15
Jul 26 '09 at 11:42
source share

Note: The code below was written for an earlier version of Django (prior to Custom Custom Models ). It contains race status and should only be used with the isolation level of a SERIALIZABLE transaction and a transaction with queries.

Your code will not work because the attributes of the field instances are read-only. I'm afraid this might be a little more complicated than you think.

If you only create user instances with the form, you can define a custom ModelForm that will apply this behavior:

 from django import forms from django.contrib.auth.models import User class UserForm(forms.ModelForm): class Meta: model = User def clean_email(self): email = self.cleaned_data.get('email') username = self.cleaned_data.get('username') if email and User.objects.filter(email=email).exclude(username=username).exists(): raise forms.ValidationError(u'Email addresses must be unique.') return email 

Then simply use this form wherever you need to create a new user.

By the way, you can use Model._meta.get_field('field_name') to get fields by name, not by position. For example:

 # The following lines are equivalent User._meta.fields[4] User._meta.get_field('email') 

UPDATE

Django's documentation recommends using the clean method for all validations, which spans several form fields, because it called after all the <FIELD>.clean and <FIELD>_clean . This means that you can (mostly) rely on the field value present in cleaned_data inside clean .

Since the form fields are checked in the order in which they are declared, I think it is sometimes advisable to place a multi-field check in the <FIELD>_clean , if the field in question appears after all other fields depend on, I I do this, so any validation errors are related to the field itself, and not to the form.

+39
Jul 22 '09 at 11:17
source share

How about using unique_together in "different" ways? So far this works for me.

 class User(AbstractUser): ... class Meta(object): unique_together = ('email',) 
+17
Oct 23 '14 at 13:45
source share

In the settings module:

 # Fix: username length is too small,email must be unique from django.contrib.auth.models import User, models User._meta.local_fields[1].__dict__['max_length'] = 75 User._meta.local_fields[4].__dict__['_unique'] = True 
+13
Sep 27 2018-11-11T00:
source share

To user, no matter where he was saved with a unique email, add it to your models:

 @receiver(pre_save, sender=User) def User_pre_save(sender, **kwargs): email = kwargs['instance'].email username = kwargs['instance'].username if not email: raise ValidationError("email required") if sender.objects.filter(email=email).exclude(username=username).count(): raise ValidationError("email needs to be unique") 

Please note that this also provides a non-empty email. However, this does not do form validation as it would be assigned, it simply throws an exception.

+6
Mar 02 '11 at 19:09
source share

Your form should look something like this.

 def clean_email(self): email = self.cleaned_data.get('email') username = self.cleaned_data.get('username') print User.objects.filter(email=email).count() if email and User.objects.filter(email=email).count() > 0: raise forms.ValidationError(u'This email address is already registered.') return email 
+6
Dec 08 2018-11-11T00:
source share

Add this somewhere:

 User._meta.get_field_by_name('email')[0]._unique = True 

and then execute SQL similar to this:

 ALTER TABLE auth_user ADD UNIQUE (email); 
+2
Jul 31 '11 at 17:45
source share

This method will not make the email field unique at the database level, but worth a try.

Use custom validator :

 from django.core.exceptions import ValidationError from django.contrib.auth.models import User def validate_email_unique(value): exists = User.objects.filter(email=value) if exists: raise ValidationError("Email address %s already exists, must be unique" % value) 

Then in forms.py:

 from django.contrib.auth.models import User from django.forms import ModelForm from main.validators import validate_email_unique class UserForm(ModelForm): #.... email = forms.CharField(required=True, validators=[validate_email_unique]) #.... 
+2
Dec 06 '11 at 18:29
source share

I think the correct answer would assure that the uniqueness check was placed inside the database (and not on the django side). Because due to the terms and conditions of the race, you can complete the duplication of letters in the database, despite the fact that, for example, pre_save performs the correct checks.

If you really need this bad, I think you can try the following approach:

  • Copy the user model into your application and change the email address to be unique.
  • Register this user model in the admin application (using the admin class from django.contrib.auth.admin )
  • Create your own authentication server that uses your model instead of django.
+2
May 26 '12 at 14:37
source share

Django has a Complete example in its documentation on how to replace and use a user model of a user so that you can add fields and use email as a username.

+2
Mar 11 '15 at 17:53
source share

Starting from version 1.2 (May 11, 2015), it is possible to dynamically import any selected registration form using the REGISTRATION_FORM settings parameter.

So, you can use something like this:

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

This is documented here .

And here is the link to the change log entry .

+2
Feb 20 '17 at 15:11
source share

One possible way to do this is to have a pre-save binding to the User object and reject the e-mail retention that already exists in the table.

+1
Jul 22 '09 at 5:42
source share

Add the following function to any models.py file. Then run makemigrations and do the migration. Tested on Django1.7

 def set_email_as_unique(): """ Sets the email field as unique=True in auth.User Model """ email_field = dict([(field.name, field) for field in MyUser._meta.fields])["email"] setattr(email_field, '_unique', True) #this is called here so that attribute can be set at the application load time set_email_as_unique() 
+1
Apr 01 '15 at 10:13
source share

The first answer here works for me when I create new users, but it fails when I try to edit the user as I exclude the username from the view. Is there any simple editing for this that will make the check independent of the username field?

I also tried to include the username field as a hidden field (since I don’t want people to edit it), but that also failed because django checked for duplicate usernames on the system.

(Sorry, this is posted as an answer, but I do not have enough comments to post it as a comment. Not sure I understand the logic of Stackoverflow.)

0
Apr 08 '10 at 19:32
source share

For this purpose you can use your own custom model. You can use email as a username or phone as a username; it can have more than one attribute.

In your settings.py you need to specify the settings AUTH_USER_MODEL = 'myapp.MyUser' below.

Here is a link that might help you. https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user

0
Jul 27 '15 at 7:24
source share

from the inherited user model, redefine the attribute correctly. It should work, since it is not useful to have django in the kernel, because it is easy to do.

-2
Jul 22 '09 at 10:21
source share

I went to \Lib\site-packages\django\contrib\auth\models and in the AbstractUser(AbstractBaseUser, PermissionsMixin): class AbstractUser(AbstractBaseUser, PermissionsMixin): I changed the email address:

 email = models.EmailField(_('email address'), **unique=True**, blank=True) 

With this, if you try to register with an email address already present in the database, you will receive a message: A user with this email address already exists.

-2
Feb 21 '16 at 13:11
source share



All Articles