Django auth.user使用唯一电子邮件

10

我使用django.auth系统,我有以下代码:

class RegisterForm(UserCreationForm):
    username = forms.RegexField(label= "Username" , max_length = 30, regex = r'^[\w]+$', error_messages = {'invalid': "This value may contain only letters, numbers and _ characters."})
    email = forms.EmailField(label = "Email")
    first_name = forms.CharField(label = "First name", required = False)
    last_name = forms.CharField(label = "Last name", required = False)

    class Meta:
        model = User
        fields = ("username", "first_name", "last_name", "email", )

    def save(self, commit = True):
        user = super(RegisterForm, self).save(commit = False)
        user.first_name = self.cleaned_data["first_name"]
        user.last_name = self.cleaned_data["last_name"]
        user.email = self.cleaned_data["email"]
        if commit:
            user.save()
        return user

我希望将电子邮件设置为唯一的,然后对表单进行验证。我该如何做到这一点?


7个回答

23

在你的模型中的某个地方:

from django.contrib.auth.models import User
User._meta.get_field('email')._unique = True

请注意unique之前的下划线。 这是实际保存信息的地方。User._meta.get_field('email').unique只是一个@property,它查看其中的内容。

这对于syncdb也应该有效,因此您可以使数据库保持一致性。

还要注意,从Django 1.5开始,您将不必执行此类操作,因为User模型将是可插拔的。


1
这在Django 1.8及以上版本中失败了。它显示权限被拒绝。 - Peter
哦我的天啊,我已经寻找了这么长时间才找到它。感谢五年前的您!在工作中被抛到一个django项目中,虽然django的一些默认类是有好处的,但如果您无法编辑/追加它们,那还有什么意义呢!但现在我可以了!您是我见过唯一写出这个的人。@Marek Brzóska 这位传奇。 - SirNail
@Irfanwani 添加此内容并运行makemigrations/migrate会创建一个迁移并更新用户模型(在我的情况下,它在venv venv\lib\site-packages\django\contrib\auth\migrations\0013_auto_20211231_1534.py中创建了一个迁移,并因此更改了用户模型定义)。由于我没有将此迁移包含在我部署的Django应用程序的git中,这导致在我的本地DEV环境与我的部署的PROD环境中使用不同的用户模型。在两个环境中,约束在常规SignUp页面中起作用。唯一的区别是在PROD中,从管理面板创建时,此约束被忽略。 - kenshuri
@kenshuri,好久不见了。我们正在尝试使电子邮件唯一(如果我说错了,请纠正我)。所以改变内置的身份验证系统并对其进行更改的最佳方法是使用AbstractUser类。请查看此答案https://dev59.com/d8Hqa4cB1Zd3GeqP3Jg6#68587018。如果您不理解,请在下面评论。 - Irfan wani
@kenshuri。对我来说也是一样的。我应该说,对我来说更糟糕。当在生产环境中进行迁移时,会出现错误消息:您的应用程序中的模型:“auth”存在未反映在迁移中的更改,因此不会被应用。运行'manage.py makemigrations'以创建新的迁移,然后重新运行'manage.py migrate'以应用它们。我将整个错误消息放在这里,以便其他人遇到相同的问题。没有任何来源明确提到“auth”应用程序,所以我花了很长时间才理解发生了什么。 - Abpostman1
显示剩余2条评论

10

将以下内容添加到您的表单中。但这并不是完美的方式,因为只使用此表单可能会出现竞态条件。我建议您在数据库级别上添加唯一约束。

def clean_email(self):
    data = self.cleaned_data['email']
    if User.objects.filter(email=data).exists():
        raise forms.ValidationError("This email already used")
    return data

添加唯一性约束的SQL语句:

ALTER TABLE auth_user ADD UNIQUE (email)

为什么这是一种好方法?另外,如果我在我的数据库字段中添加“unique = True”,这样做可以吗? - Fred Collins
你不能在不使用猴子补丁或修补Django的情况下更改Django auth.user模型。因此,你不能轻松地向User模型添加unique=True。 - mumino

1

我不确定如何使用它,但是

from django.contrib.auth.models import User
User._meta.get_field_by_name('email')[0].unique=True

应该这样做。我猜这个要放在你的models.py中,在对auth模型运行syncdb之前。我自己也要尝试一下。


1
你可以在 models.py 中添加以下代码,使得电子邮件地址成为唯一的(unique),甚至允许其为空(null)。
from django.db import models
from django.contrib.auth.models import User

User.email = models.EmailField(_("email address"), blank=True, null=True, unique=True)

已在Django 4.0.3上进行测试


0
在注册过程中,我发现一个问题,即在Django身份验证中电子邮件不是必需的,但是在简单验证时,如果我们没有提供电子邮件,则会出现500错误,因为我们必须在后端检查电子邮件。
因此,为了使其成为必填项,请添加到registrationSerializer中;
extra_kwargs = {'email': {'required': True}}

对于唯一的电子邮件地址,其他答案已经有所显示。


0

我使用django.auth。我应该使用什么代替它? - Fred Collins

0

你可以使用抽象用户模型中的这个来做同样的事情:

class User(AbstractUser):
...

class Meta:
    unique_together = ('email',)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接