我需要通过确保电子邮件字段条目唯一来修补contrib.auth
的标准用户模型:
User._meta.fields[4].unique = True
代码中哪个地方最适合这样做?
我想避免使用数字字段[4] 。用户字段['email'] 更好,但字段不是字典,只有列表。
另一个想法可能是打开新故障单并在settings.py
内上传带有新参数的补丁:
AUTH_USER_EMAIL_UNIQUE = True
有关在Django用户模型中实现电子邮件地址唯一性的最正确方法的任何建议吗?
答案 0 :(得分:48)
<强>注意:强> 下面的代码是为旧版本的Django编写的(在引入Custom User Models之前)。它包含竞争条件,和 应仅用于
SERIALIZABLE
的事务隔离级别 和请求范围的事务。
您的代码无效,因为字段实例的属性是只读的。我担心这可能比你想的要复杂得多。
如果您只使用表单创建User实例,则可以定义强制执行此行为的自定义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')
Django文档建议您对涵盖多个表单字段的所有验证使用clean
方法,因为它是在所有<FIELD>.clean
和<FIELD>_clean
方法之后调用的。这意味着您(大部分)可以依赖于cleaned_data
内clean
中的字段值。
由于表单字段按照声明的顺序进行验证,我认为偶尔在<FIELD>_clean
方法中放置多字段验证是可以的,只要有问题的字段出现在所有其他字段之后它就可以了依赖于取决于。我这样做是因为任何验证错误都与字段本身相关联,而不是与表单相关联。
答案 1 :(得分:32)
如何在&#34;不同的&#34;中使用unique_together
呢?办法?到目前为止它对我有用。
class User(AbstractUser):
...
class Meta(object):
unique_together = ('email',)
答案 2 :(得分:15)
在设置模块中:
# 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
答案 3 :(得分:14)
答案 4 :(得分:8)
您的表单应该是这样的。
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
答案 5 :(得分:6)
只需在任何应用程序的models.py中使用以下代码
from django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
答案 6 :(得分:6)
要确保用户(无论身在何处)使用唯一的电子邮件保存,请将其添加到您的模型中:
@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")
请注意,这也可以确保非空白电子邮件。但是,这不会进行表格验证,因为它会被占用,只会引发异常。
答案 7 :(得分:3)
Django在其文档中有Full Example如何替换和使用自定义用户模型,因此您可以添加字段并使用电子邮件作为用户名。
答案 8 :(得分:2)
此方法不会使电子邮件字段在数据库级别上唯一,但值得尝试。
使用自定义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 :(得分:2)
我认为正确的答案可以确保在数据库中放置唯一性检查(而不是在django端)。因为时间和竞争条件,您可能会在数据库中以重复的电子邮件结束,尽管例如pre_save
进行了正确的检查。
如果你真的需要这么做,我猜你可能会尝试以下方法:
django.contrib.auth.admin
中的管理类)答案 10 :(得分:2)
在任何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()
答案 11 :(得分:2)
从1.2版(2015年5月11日)开始,有一种方法可以使用设置选项REGISTRATION_FORM
动态导入任何选定的注册表单。
所以,人们可以使用这样的东西:
REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'
记录在案here。
这是指向changelog entry的链接。
答案 12 :(得分:2)
Django不允许直接编辑User对象,但您可以添加pre_save信号并实现唯一的电子邮件。对于创建信号,您可以关注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
答案 13 :(得分:2)
执行此操作的一种可能方法是在User对象上设置预保存挂钩,并拒绝保存表中已存在的电子邮件。
答案 14 :(得分:1)
在此处添加:
User._meta.get_field_by_name('email')[0]._unique = True
然后执行类似于此的SQL:
ALTER TABLE auth_user ADD UNIQUE (email);
答案 15 :(得分:0)
这里的第一个答案是在我创建新用户时为我工作,但在我尝试编辑用户时失败,因为我从视图中排除了用户名。是否有一个简单的编辑,使检查独立于用户名字段?
我还尝试将用户名字段包含为隐藏字段(因为我不希望人们编辑它),但这也失败了因为django正在检查系统中的重复用户名。
(抱歉,这是作为答案发布的,但我缺乏将其作为评论发布的信誉。不确定我理解Stackoverflow的逻辑。)
答案 16 :(得分:0)
您可以使用自己的自定义用户模型来实现此目的。您可以使用电子邮件作为用户名或电话作为用户名,可以有多个属性。
在settings.py中,您需要指定以下设置 AUTH_USER_MODEL =&#39; myapp.MyUser&#39;。
这是可以帮助您的链接。 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user
答案 17 :(得分:-2)
来自用户继承的模型,正确地重新定义属性。它应该有效,因为它在django核心中没有用,因为它很简单。
答案 18 :(得分:-3)
我去了\Lib\site-packages\django\contrib\auth\models
在班级AbstractUser(AbstractBaseUser, PermissionsMixin):
我将电子邮件更改为:
email = models.EmailField(_('email address'), **unique=True**, blank=True)
如果您尝试使用数据库中已存在的电子邮件地址进行注册,您将收到消息:具有此电子邮件地址的用户已存在。