使用户电子邮件成为唯一的Django

时间:2018-11-24 18:58:04

标签: django

当用户注册时,如何使Django用户电子邮件唯一?

forms.py

class SignUpForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")

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

我使用django.contrib.auth.models用户。 我是否需要在模型中覆盖用户。当前,该模型未引用用户。

views.py

class SignUp(generic.CreateView):
    form_class = SignUpForm
    success_url = reverse_lazy('login')
    template_name = 'signup.html'

感谢您的想法。

8 个答案:

答案 0 :(得分:7)

最好的答案是使用CustomUser,方法是将AbstractUser子类化,然后在其中放置唯一的电子邮件地址。例如:

from django.contrib.auth.models import AbstractUser


class CustomUser(AbstractUser):
    email = models.EmailField(unique=True)

并使用AUTH_USER_MODEL="app.CustomUser"更新设置。

但是,如果您不必将唯一的电子邮件存储在数据库中或可能不将其用作用户名字段,则可以更新表单的clean方法以进行验证。例如:

class YourForm(UserCreationForm):

    def clean(self):
       email = self.cleaned_data.get('email')
       if User.objects.filter(email=email).exists():
            raise ValidationError("Email exists")
       return self.cleaned_data

更新

如果您处于项目中期,则可以按照documentation进行更改迁移的方法,简而言之是:

  1. 备份数据库
  2. 创建一个与auth.User相同的自定义用户模型,将其命名为User(许多表保持相同的名称)并设置db_table ='auth_user'(因此它使用同一表)
  3. 删除所有迁移文件(__init__.py
  4. 删除表django_migrations中的所有条目
  5. 使用python manage.py makemigrations
  6. 创建所有迁移文件
  7. 通过python manage.py migrate --fake
  8. 运行假迁移
  9. 取消设置db_table,对自定义模型进行其他更改,生成迁移并应用

但是,如果您刚刚开始,请删除迁移目录中__init__.py以外的数据库和迁移文件。然后创建一个新的数据库,通过python manage.py makemigrations创建一组新的迁移,并通过python manage.py migrate应用迁移。

对于其他模型中的引用,可以将其引用到settings.AUTH_USER_MODEL以避免将来出现任何问题。例如:

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)

它将自动引用当前的用户模型。

答案 1 :(得分:1)

您可能对以下内容感兴趣:

django-user-unique-email

可重用的用户模型,具有必需的唯一电子邮件字段和项目中期支持。

它定义了重用原始表(auth_user)的自定义用户模型(如果存在)。如果需要(添加到现有项目中时),它将以正确的顺序重新创建应用的迁移历史记录。

我将不胜感激。

答案 2 :(得分:0)

Django的文档中有一个很好的例子-https://docs.djangoproject.com/en/2.1/topics/auth/customizing/#a-full-example

您必须在AbstractBaseUser模型中将电子邮件字段声明为unique=True

class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

答案 3 :(得分:0)

这是工作代码

在您的任何模型中使用以下代码段。py

models.py

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

django版本:3.0.2

参考:Django auth.user with unique email

答案 4 :(得分:0)

Django 3.1的工作代码

models.py

from django.contrib.auth.models import User

User._meta.get_field('email')._unique = True
SETTINGS.PY
AUTHENTICATION_BACKENDS = [
     'django.contrib.auth.backends.ModelBackend'
]

答案 5 :(得分:0)

比使用 AbstractBaseUser 更好的方法

#forms.py
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
from django.contrib.auth.form import UserCreationForm
from some_app.validators import validate_email

def validate_email(value):
    if User.objects.filter(email = value).exists():
        raise ValidationError((f"{value} is taken."),params = {'value':value})

class UserRegistrationForm(UserCreationForm):
        email = forms.EmailField(validators = [validate_email])
        
        class Meta:
            model = User
        fields = ['username', 'email', 'password1', 'password2']    
    

答案 6 :(得分:0)

如果使用从 AbstractBaseUser 继承的 CustomUser 模型,您可以覆盖 full_clean() 方法来验证您指定的模型字段的唯一约束 unique=True。这比表单(即 FormClass)验证更安全。

示例

from django.contrib.auth.models import AbstractBaseUser
from django.db import models

class CustomUser(AbstractBaseUser):
    email = models.EmailField(unique=True)
    # ...


    def full_clean(self, **kwargs):
        """
        Call clean_fields(), clean(), and validate_unique() on the model.
        Raise a ValidationError for any errors that occur.
        """
        super().full_clean()

注意:在 Django 3.1

上测试

答案 7 :(得分:0)

简单的方法: 你可以用信号 示例

from django.db.models.signals import post_save, pre_save
from django.dispatch import  receiver
from django.contrib.auth.models import User
from django.forms import ValidationError

@receiver(pre_save, sender=User)
def check_email(sender, instance, **kwargs):
    email = instance.email
    if sender.objects.filter(email=email).exclude(username=instance.username).exists():
        raise ValidationError('Email Already Exists')