Как сделать поле электронной почты уникальным в модели пользователя из contrib.авторизации в Django



мне нужно исправить стандартную пользовательскую модель contrib.auth гарантируя, что запись в поле электронной почты уникальна:



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


где лучшее место в коде, чтобы сделать это?



Я хочу избежать использования числа поля[4]. Это лучше для пользователя поля ['email'], а поля - это не словарь, только список.



другая идея может заключаться в том, чтобы открыть новый билет и загрузить патч с новым параметром внутри settings.py:



AUTH_USER_EMAIL_UNIQUE = True


любые предложения о наиболее правильном способе достижения уникальности адреса электронной почты в модели пользователя Django?

1345   19  

19 ответов:

внимание: Приведенный ниже код был написан для более старой версии (до Custom Пользовательские Модели были введены). Он содержит состояние гонки, и следует использовать только с уровнем изоляции транзакций SERIALIZABLE и транзакции с областью запроса.

ваш код не будет работать, так как атрибуты экземпляров полей доступны только для чтения. Я боюсь, что это может быть немного сложнее, чем ты размышляющий.

если вы будете создавать только пользовательские экземпляры с формой, вы можете определить пользовательскую модель, которая обеспечивает это поведение:

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

тогда просто используйте эту форму везде, где вам нужно создать нового пользователя.

кстати, вы можете использовать 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-Регистрация иметь форму с проверкой уникальности поля электронной почты: RegistrationFormUniqueEmail

пример использования здесь

чтобы гарантировать, что пользователь, независимо от того, где, будет сохранен с уникальным электронным письмом, добавьте это в свои модели:

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

обратите внимание, что это обеспечивает непустую электронную почту тоже. Однако это не делает проверку форм, как было бы присвоено, просто вызывает исключение.

ваша форма должна выглядеть примерно так.

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

один из возможных способов сделать это, чтобы сохранить крючок на объект пользователя и отвергают сохранение электронной почты уже существует в таблице.

добавить где-то так:

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

и затем выполните SQL, подобный этому:

ALTER TABLE auth_user ADD UNIQUE (email);

Я думаю, что правильный ответ будет гарантировать, что проверка уникальности была размещена внутри базы данных (а не на стороне django). Потому что из-за времени и условий гонки вы можете закончить с дубликатами писем в базе данных, несмотря на то, например pre_save Это делает правильные проверки.

Если вам действительно это нужно, я думаю, вы можете попробовать следующий подход:

  1. скопируйте модель пользователя в свое собственное приложение и измените поле электронной почты, чтобы быть уникальным.
  2. зарегистрируйте эту пользовательскую модель в приложении admin (используя класс admin от django.contrib.auth.admin)
  3. создайте свой собственный сервер аутентификации, который использует вашу модель вместо django one.

этот метод не сделать поле email уникальность на уровне базы данных, но это стоит попробовать.

использовать пользовательские оценщика:

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)

затем в 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])
    #....

у Джанго есть Полный Пример в его документации о том, как заменить и использовать пользовательскую модель пользователя, чтобы вы могли добавлять поля и использовать электронную почту в качестве имени пользователя.

добавить функцию ниже в любой из models.py файл. Затем запустите makemigrations и выполните миграцию. Протестировано на 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.2 (11 мая 2015 г.) появилась возможность динамически импортировать любую выбранную регистрационную форму с помощью опции настройки REGISTRATION_FORM.

Итак, можно было бы использовать что-то вроде этого:

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

Это документировано здесь.

и вот ссылка запись в changelog.

Django не позволяет напрямую редактировать пользовательский объект, но вы можете добавить сигнал pre_save и получить уникальную электронную почту. для создания сигналов u может следовать https://docs.djangoproject.com/en/2.0/ref/signals/. затем добавьте следующее к вашему 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

первый ответ здесь работает для меня, когда я создаю новых пользователей, но он терпит неудачу, когда я пытаюсь редактировать пользователя, так как я исключаю имя пользователя из представления. Есть ли простое редактирование для этого, которое сделает проверку независимой от поля имени пользователя?

Я также попытался включить поле username в качестве скрытого поля (так как я не хочу, чтобы люди его редактировали), но это тоже не удалось, потому что django проверял дубликаты имен пользователей в системе.

(к сожалению это опубликовано в качестве ответа, но мне не хватает creds, чтобы опубликовать его в качестве комментария. Не уверен, что я понимаю логику Stackoverflow на этом.)

вы можете использовать свою собственную пользовательскую модель для этой цели. Вы можете использовать электронную почту в качестве имени пользователя или телефон в качестве имени пользователя , может иметь более одного атрибута.

в вашем settings.py вам нужно указать ниже настройки AUTH_USER_MODEL = ' myapp.Мой_логин'.

вот ссылка, которая может помочь вам . https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user

просто используйте ниже код в models.py любого приложения

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

от унаследованной пользователем модели, переопределите атрибут правильно. Он должен работать, так как это не полезно иметь это в ядре django, потому что это просто сделать.

пошел к \Lib\site-packages\django\contrib\auth\models и в классе AbstractUser(AbstractBaseUser, PermissionsMixin): Я изменил адрес электронной почты, чтобы быть:

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

при этом при попытке регистрации с адресом электронной почты уже существует в базе вы получите сообщение: пользователь с таким адресом электронной почты уже существует.

Comments

    Ничего не найдено.