如何使电子邮件字段在Django中的contrib.auth模型用户中唯一

我需要通过确保电子邮件字段条目是唯一的来修补contrib.auth的标准用户模型:

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

哪里是最好的代码来做到这一点?

我想避免使用数字字段[4] 。 用户字段['email']更好,但字段不是字典,只有列表。

另一个想法可能是打开一个新票,并在settings.py中用新参数上传一个补丁:

 AUTH_USER_EMAIL_UNIQUE = True 

关于在Django用户模型中实现电子邮件唯一性的最正确方法的任何build议?

您的代码将不起作用,因为字段实例的属性是只读的。 我担心这可能比你想象的要复杂一点。

如果您只能使用表单创buildUser实例,则可以定义一个强制实施此行为的自定义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 

然后,只要你需要创build一个新的用户使用这种forms。

顺便说一句,你可以使用Model._meta.get_field('field_name')来获取字段的名称,而不是位置。 举个例子:

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

UPDATE
Django文档build议您对所有跨多个表单字段的validation使用clean方法,因为它在所有<FIELD>.clean<FIELD>_clean方法之后调用。 这意味着你可以(大部分)依赖cleaned_data的字段值。

由于表单字段是按照声明的顺序进行validation的,所以我认为偶尔将多字段validation放在<FIELD>_clean方法中是可以的,只要问题字段出现在所有依赖的其他字段之后。 我这样做,所以任何validation错误都与该领域本身,而不是forms。

这是惊人的,但我find了一个最好的解决scheme!

Django的注册forms与电子邮件字段检查唯一性:RegistrationFormUniqueEmail

在这里使用的例子

怎么样以不同的方式使用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 

为了确保用户,不pipe在哪里,保存一个唯一的电子邮件,将其添加到您的模型:

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

请注意,这也确保了非空邮件。 然而,这不会做表格validation,只会引发一个例外。

你的表单应该看起来像这样。

 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. 在pipe理员应用程序中注册此用户模型(使用django.contrib.auth.adminpipe理员类)
  3. 创build自己的身份validation后端,使用您的模型,而不是Django的。

此方法不会使数据库级别的电子邮件字段唯一,但值得尝试。

使用自定义validation器 :

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

Django有关如何replace和使用自定义用户模型的文档的完整示例 ,因此您可以添加字段并使用电子邮件作为用户名。

从版本1.2(2015年5月11日)开始,可以使用设置选项REGISTRATION_FORM来dynamic导入任何选定的registry单。

所以,可以使用这样的东西:

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

这是在这里logging 。

这里是更新日志条目的链接。

一种可能的方法是在User对象上有一个预保存钩子,并拒绝表中已存在的电子邮件的保存。

在任何models.py文件中添加下面的函数。 然后运行makemigrations并迁移。 在Django1.7上testing

 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() 

当我创build新用户时,第一个答案是为我工作,但是当我尝试编辑用户时失败,因为我从视图中排除了用户名。 有没有一个简单的编辑,这将使独立的用户名字段的检查?

我也尝试将用户名字段作为隐藏字段(因为我不希望人们编辑它),但也是因为django在系统中检查重复的用户名而失败。

(对不起,这是张贴的答案,但我缺乏信誉张贴作为评论。不知道我理解Stackoverflow的逻辑。)

您可以使用自己的自定义用户模型来达到此目的。 您可以使用电子邮件作为用户名或电话作为用户名,可以有多个属性。

在你的settings.py中,你需要指定下面的设置AUTH_USER_MODEL ='myapp.MyUser'。

这里是可以帮助你的链接。 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user

从用户inheritance的模型,正确地重新定义属性。 它应该工作,因为在django核心,这是不是很有用,因为它很容易做到。

我去了\Lib\site-packages\django\contrib\auth\models和类AbstractUser(AbstractBaseUser, PermissionsMixin):我改变了电子邮件为:

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

有了这个如果你尝试注册数据库中已经存在的电子邮件地址,你会得到消息:具有这个电子邮件地址的用户已经存在。