Programing

Django의 contrib.auth에서 모델 사용자의 이메일 필드를 고유하게 만드는 방법

crosscheck 2020. 11. 30. 07:50
반응형

Django의 contrib.auth에서 모델 사용자의 이메일 필드를 고유하게 만드는 방법


contrib.auth이메일 필드 항목이 고유한지 확인하여 의 표준 사용자 모델을 패치해야합니다 .

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

코드에서 가장 좋은 위치는 어디입니까?

숫자 필드 사용을 피하고 싶습니다 [4] . fields [ 'email'] 을 사용하는 것이 더 좋지만 필드 는 사전이 아니라 목록 만 있습니다.

또 다른 아이디어는 새 티켓을 열고 내부에 새 매개 변수가있는 패치를 업로드하는 것입니다 settings.py.

AUTH_USER_EMAIL_UNIQUE = True

Django 사용자 모델에서 이메일 주소 고유성을 달성하는 가장 올바른 방법에 대한 제안이 있습니까?


주의 : 아래 코드는 이전 버전의 Django 용으로 작성되었습니다 ( 사용자 지정 사용자 모델 이 도입 되기 전 ). 경쟁 조건을 포함하며 트랜잭션 격리 수준 SERIALIZABLE및 요청 범위 트랜잭션 에서만 사용해야 합니다.

필드 인스턴스의 속성이 읽기 전용이므로 코드가 작동하지 않습니다. 당신이 생각하는 것보다 조금 더 복잡 할지도 모릅니다.

양식을 사용하여 사용자 인스턴스 만 생성하는 경우이 동작을 적용하는 사용자 정의 ModelForm을 정의 할 수 있습니다.

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

그런 다음 새 사용자를 만들어야 할 때마다이 양식을 사용하십시오.

BTW를 사용 Model._meta.get_field('field_name')하면 위치가 아닌 이름으로 필드를 가져올 수 있습니다 . 예를 들면 다음과 같습니다.

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

최신 정보

Django 문서에서는 clean모든 <FIELD>.clean<FIELD>_clean메서드 다음에 호출되므로 여러 양식 필드에 걸쳐있는 모든 유효성 검사에이 메서드를 사용하도록 권장합니다 . 이것은 (대부분) cleaned_data에서 필드의 값이 존재하는 것에 의존 할 수 있음을 의미합니다 clean.

양식 필드는 선언 된 순서대로 유효성이 검사되기 때문에 <FIELD>_clean문제의 필드가 종속 된 다른 모든 필드 뒤에 표시 되는 한 메서드 에 때때로 다중 필드 유효성 검사를 배치하는 것이 좋습니다 . 이렇게하면 유효성 검사 오류가 양식이 아닌 필드 자체와 연결됩니다.


unique_together"다른"방식으로 사용 하는 것은 어떻습니까? 지금까지 그것은 나를 위해 작동합니다.

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

설정 모듈에서 :

# 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

놀랍지 만 가장 좋은 해결책을 찾았습니다!

django-registration 에는 이메일 필드의 고유성을 확인하는 양식이 있습니다. RegistrationFormUniqueEmail

여기 에 사용 예


양식은 다음과 같아야합니다.

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

사용자가 어디에 있든 고유 한 이메일로 저장되도록하려면 다음을 모델에 추가하십시오.

@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")

이렇게하면 비어 있지 않은 이메일도 보장됩니다. 그러나 이것은 적절한 양식 유효성 검사를 수행하지 않고 예외를 발생시킵니다.


모든 앱의 models.py에서 아래 코드를 사용하기 만하면됩니다.

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

Django는 사용자 지정 사용자 모델을 대체하고 사용하는 방법에 대한 설명서에 대한 전체 예제 를 제공하므로 필드를 추가하고 사용자 이름으로 이메일을 사용할 수 있습니다.


이를 수행하는 한 가지 가능한 방법은 User 개체에 사전 저장 후크를 설정하고 테이블에 이미 존재하는 전자 메일 저장을 거부하는 것입니다.


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

If you really need this badly I 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.

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

Use 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])
    #....

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

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

So, one could use something like this:

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

This is documented here.

And here's the link to the changelog entry.


Django does not allow direct editing User object but you can add pre_save signal and achieve unique email. for create signals u can follow https://docs.djangoproject.com/en/2.0/ref/signals/. then add the following to 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

Add somewhere this:

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

and then execute SQL similar to this:

ALTER TABLE auth_user ADD UNIQUE (email);

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

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

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


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

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

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


from an User inherited model, redefine the attribute correctly. It should work, as is it's not usefull to have that in django core because it's simple to do.


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

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

With this if you try to register with email address already present in the database you will get message: User with this Email address already exists.

참고URL : https://stackoverflow.com/questions/1160030/how-to-make-email-field-unique-in-model-user-from-contrib-auth-in-django

반응형