[ACCEPTED]-How to make email field unique in model User from contrib.auth in Django-django-models

Accepted answer
Score: 51

Caution: The code below was written for an older 27 version of Django (before Custom User Models were introduced). It 26 contains a race condition, and should 25 only be used with a Transaction Isolation 24 Level of SERIALIZABLE and request-scoped transactions.

Your 23 code won't work, as the attributes of field 22 instances are read-only. I fear it might 21 be a wee bit more complicated than you're 20 thinking.

If you'll only ever create User 19 instances with a form, you can define a 18 custom ModelForm that enforces 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 17 just use this form wherever you need to 16 create a new user.

BTW, you can use Model._meta.get_field('field_name') to get 15 fields by name, rather than by position. So 14 for example:

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

UPDATE

The Django documentation recommends 13 you use the clean method for all validation that 12 spans multiple form fields, because it's 11 called after all the <FIELD>.clean and <FIELD>_clean methods. This 10 means that you can (mostly) rely on the 9 field's value being present in cleaned_data from within 8 clean.

Since the form fields are validated in 7 the order they're declared, I think it's 6 okay to occasionally place multi-field validation 5 in a <FIELD>_clean method, so long as the field in question 4 appears after all other fields it depends 3 on. I do this so any validation errors are 2 associated with the field itself, rather 1 than with the form.

Score: 41

What about using unique_together in a "different" way? So 1 far it works for me.

class User(AbstractUser):
    ...
    class Meta(object):
        unique_together = ('email',)
Score: 19

Simply use below code in models.py of any 1 app

from django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
Score: 17

In 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

0

Score: 15

It's amazing, but I found a best solution 3 for me!

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

example 1 of usage here

Score: 8

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

0

Score: 6

To ensure a User, no matter where, be saved 4 with a unique email, add this 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")

Note 3 that this ensures non-blank email too. However, this 2 doesn't do forms validation as would be 1 appropriated, just raises an exception.

Score: 3

Django has a Full Example on its documentation on how 2 to substitute and use a Custom User Model, so 1 you can add fields and use email as username.

Score: 2

One possible way to do this is to have a 3 pre-save hook on the User object and reject 2 the save of the email already exists in 1 the table.

Score: 2

This method won't make email field unique 2 at the database level, but it's worth trying.

Use 1 a 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])
    #....
Score: 2

I think that the correct answer would assure 7 that uniqueness check was placed inside 6 the database (and not on the django side). Because 5 due to timing and race conditions you might 4 end with duplicate emails in the database 3 despite having for example pre_save that does proper 2 checks.

If you really need this badly I 1 guess you might try following approach:

  1. Copy User model to your own app, and change field email to be unique.
  2. Register this user model in the admin app (using admin class from django.contrib.auth.admin)
  3. Create your own authentication backend that uses your model instead of django one.
Score: 2

Add the below function in any of the models.py 2 file. Then run makemigrations and migrate. Tested 1 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()
Score: 2

Since version 1.2 (May 11th, 2015) there 5 has been a way to dynamically import any 4 chosen registration form using the settings 3 option REGISTRATION_FORM.

So, one could use something like 2 this:

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

This is documented here.

And here's the 1 link to the changelog entry.

Score: 2

Django does not allow direct editing User 4 object but you can add pre_save signal and 3 achieve unique email. for create signals 2 u can follow https://docs.djangoproject.com/en/2.0/ref/signals/. then add the following to 1 your signals.py

 @receiver(pre_save, sender=User)
def check_email(sender,instance,**kwargs):
    try:
        usr = User.objects.get(email=instance.email)
        if usr.username == instance.username:
            pass
        else:
            raise Exception('EmailExists')
    except User.DoesNotExist:
        pass
Score: 1

Add somewhere this:

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

and then execute SQL 1 similar to this:

ALTER TABLE auth_user ADD UNIQUE (email);
Score: 0

The first answer here is working for me 12 when I'm creating new users, but it fails 11 when I try to edit a user, since I am excluding 10 the username from the view. Is there a simple 9 edit for this that will make the check independent 8 of the username field?

I also tried including 7 the username field as a hidden field (since 6 I don't want people to edit it), but that 5 failed too because django was checking for 4 duplicate usernames in the system.

(sorry 3 this is posted as an answer, but I lack 2 the creds to post it as a comment. Not sure 1 I understand Stackoverflow's logic on that.)

Score: 0

You can use your own custom user model for 6 this purpose. You can use email as username 5 or phone as username , can have more than 4 one attribute.

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

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

More Related questions