Как сделать поле электронной почты уникальным в модели пользователя из contrib.авторизации в Django
мне нужно исправить стандартную пользовательскую модель contrib.auth гарантируя, что запись в поле электронной почты уникальна:
User._meta.fields[4].unique = True
где лучшее место в коде, чтобы сделать это?
Я хочу избежать использования числа поля[4]. Это лучше для пользователя поля ['email'], а поля - это не словарь, только список.
другая идея может заключаться в том, чтобы открыть новый билет и загрузить патч с новым параметром внутри settings.py:
AUTH_USER_EMAIL_UNIQUE = True
любые предложения о наиболее правильном способе достижения уникальности адреса электронной почты в модели пользователя Django?
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Это делает правильные проверки.Если вам действительно это нужно, я думаю, вы можете попробовать следующий подход:
- скопируйте модель пользователя в свое собственное приложение и измените поле электронной почты, чтобы быть уникальным.
- зарегистрируйте эту пользовательскую модель в приложении admin (используя класс admin от
django.contrib.auth.admin)- создайте свой собственный сервер аутентификации, который использует вашу модель вместо 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