Подтвердить что ты не робот

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

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

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

Где лучшее место в коде для этого?

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

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

AUTH_USER_EMAIL_UNIQUE = True

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

4b9b3361

Ответ 1

Удивительно, но я нашел лучшее решение для меня!

django-registration имеют форму с проверкой уникальности поля электронной почты: RegistrationFormUniqueEmail

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

Ответ 2

Внимание:Код ниже был написан для более ранней версии Django (до Custom Пользовательские модели). Он содержит состояние гонки и должен использоваться только с уровнем изоляции транзакции 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

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

Кстати, вы можете использовать Model._meta.get_field('field_name') для получения полей по имени, а не по положению. Так, например:

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

UPDATE

Документация Django рекомендует использовать метод clean для всех проверок, который охватывает несколько полей формы, потому что он вызвал после всех методов <FIELD>.clean и <FIELD>_clean. Это означает, что вы можете (в основном) полагаться на значение поля, присутствующее в cleaned_data, внутри clean.

Поскольку поля формы проверяются в том порядке, в котором они объявлены, я думаю, что иногда бывает целесообразно размещать многополевую проверку в методе <FIELD>_clean, если поле, о котором идет речь, появляется после того, как все остальные поля зависят от, Я делаю это, поэтому любые ошибки проверки связаны с самим полем, а не с формой.

Ответ 3

Как насчет использования unique_together в "разных" способах? Пока это работает для меня.

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

Ответ 4

В модуле настроек:

# 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

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

Добавьте где-нибудь это:

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

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

ALTER TABLE auth_user ADD UNIQUE (email);

Ответ 8

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

Использовать пользовательский 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)

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

Ответ 9

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

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

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

Ответ 10

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

Ответ 11

Начиная с версии 1.2 (11 мая 2015 г.) существует возможность динамически импортировать любую выбранную регистрационную форму с помощью параметра настроек REGISTRATION_FORM.

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

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

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

И здесь ссылка на запись в журнале изменений.

Ответ 12

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

Ответ 13

Добавьте следующую функцию в любой файл 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()

Ответ 14

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

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

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

Ответ 15

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

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

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

Ответ 16

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

Ответ 17

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

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

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