如何在模型用户中使用Django中的contrib.auth创建独特的电子邮件字段

ram*_*sus 62 django django-models

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

User._meta.fields[4].unique = True
Run Code Online (Sandbox Code Playgroud)

代码中最好的位置在哪里?

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

另一个想法可能是打开一个新票证并上传一个带有新参数的补丁settings.py:

AUTH_USER_EMAIL_UNIQUE = True
Run Code Online (Sandbox Code Playgroud)

有关在Django用户模型中实现电子邮件地址唯一性的最正确方法的任何建议吗?

elo*_*0ka 50

警告: 下面的代码是为旧版本的Django编写的(在引入自定义用户模型之前).它包含竞争条件,并且只应与事务隔离级别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
Run Code Online (Sandbox Code Playgroud)

然后只需在需要创建新用户的地方使用此表单.

顺便说一句,您可以使用Model._meta.get_field('field_name')按名称而不是按位置获取字段.例如:

# The following lines are equivalent
User._meta.fields[4]
User._meta.get_field('email')
Run Code Online (Sandbox Code Playgroud)

UPDATE

Django文档建议您将该clean方法用于跨越多个表单字段的所有验证,因为它在所有<FIELD>.clean<FIELD>_clean方法之后调用.这意味着您(大部分)可以依赖于cleaned_data内部存在的字段值clean.

由于表单字段按照它们声明的顺序进行验证,我认为偶尔在<FIELD>_clean方法中放置多字段验证是可以的,只要有问题的字段出现在它依赖的所有其他字段之后.我这样做是因为任何验证错误都与字段本身相关联,而不是与表单相关联.

  • @Viet:我添加了一个.exclude(用户名=用户名)来解决这个问题. (2认同)

eil*_*rra 37

那么unique_together以"不同"的方式使用呢?到目前为止它对我有用.

class User(AbstractUser):
    ...
    class Meta(object):
        unique_together = ('email',)
Run Code Online (Sandbox Code Playgroud)


小智 17

在设置模块中:

# 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
Run Code Online (Sandbox Code Playgroud)

  • `User._meta.get_field('email').__ dict __ ['_ unique'] = True`或`User._meta.get_field('email')._ unique = True`这两个应该工作 (4认同)
  • 我需要把它放到我的`models`模块中. (3认同)

ram*_*sus 15

这太棒了,但我找到了最适合我的解决方案!

django-registration具有检查电子邮件字段唯一性的形式:RegistrationFormUniqueEmail

这里使用的例子

  • 不要成为混蛋,但我认为你的意思是"独特",而不是"独特". (8认同)
  • 链接已经死了.http://www.copyandwaste.com/posts/view/django-registration-require-a-unique-email-address-for-registration/和http://stackoverflow.com/questions/2131533/django-registration-force -unique-e-mail了解更多信息 (7认同)

Nid*_*wal 9

只需在任何应用程序的models.py中使用以下代码

from django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
Run Code Online (Sandbox Code Playgroud)

  • 这是我发现的最简单的解决方案。有时候可能需要创建一个自定义用户模型。但是,如果罐装Django用户模型满足了使标准字段唯一的愿望,那么就可以满足所有要求,那么就无需使事情变得复杂。感谢您的出色回答-尽管您可能想补充一点,但需要执行迁移才能更改该数据库中的字段。 (3认同)

小智 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
Run Code Online (Sandbox Code Playgroud)


zVi*_*tor 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")
Run Code Online (Sandbox Code Playgroud)

请注意,这也确保了非空白电子邮件.但是,这不会进行表格验证,因为它会被占用,只会引发异常.