如何使电子邮件字段在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
会进行适当的检查。
如果你确实需要这个,我猜你可能会尝试下面的方法:
- 将用户模型复制到您自己的应用程序,并将字段电子邮件更改为唯一。
- 在pipe理员应用程序中注册此用户模型(使用
django.contrib.auth.admin
pipe理员类) - 创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)
有了这个如果你尝试注册数据库中已经存在的电子邮件地址,你会得到消息:具有这个电子邮件地址的用户已经存在。