Py学习  »  Django

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

laz • 5 年前 • 1446 次点击  

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

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

代码中最好的地方在哪里?

我想避免用这个号码 字段〔4〕 . 最好是用户 字段[电子邮件] 但是 领域 不是字典,只是列表。

另一个想法可能是打开一个新的记录单并上传一个包含新参数的补丁。 settings.py :

AUTH_USER_EMAIL_UNIQUE = True

对于在django用户模型中实现电子邮件地址唯一性的最正确方法有什么建议吗?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/30685
 
1446 次点击  
文章 [ 19 ]  |  最新文章 5 年前
Azur
Reply   •   1 楼
Azur    8 年前

我去了 \Lib\site-packages\django\contrib\auth\models 在课堂上 AbstractUser(AbstractBaseUser, PermissionsMixin): 我将电子邮件改为:

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

如果您尝试使用数据库中已存在的电子邮件地址注册,则会收到消息:具有此电子邮件地址的用户已存在。

amirouche
Reply   •   2 楼
amirouche    14 年前

从用户继承的模型中,正确地重新定义属性。它应该是有效的,因为在Django核心中拥有它是不有用的,因为它很容易做到。

user2772346
Reply   •   3 楼
user2772346    8 年前

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

在settings.py中,需要指定以下设置 auth_user_model='myapp.myuser'。

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

mlissner
Reply   •   4 楼
mlissner    13 年前

这里的第一个答案在我创建新用户时对我有效,但在我尝试编辑用户时失败,因为我将用户名从视图中排除。是否有一个简单的编辑可以使检查独立于用户名字段?

我还尝试将用户名字段包括为隐藏字段(因为我不想让人们编辑它),但这也失败了,因为Django正在检查系统中的重复用户名。

(很抱歉,这是作为答案发布的,但我缺乏将其作为评论发布的可信度。我不确定我是否理解StackOverflow的逻辑。)

nikhil patil
Reply   •   5 楼
nikhil patil    5 年前

Django不允许直接编辑用户对象,但您可以添加预存信号并实现独特的电子邮件。对于创建信号,U可以跟随 https://docs.djangoproject.com/en/2.0/ref/signals/ . 然后将以下内容添加到信号中。

 @receiver(pre_save, sender=User)
def check_email(sender,instance,**kwargs):
    try:
        usr = User.objects.get(email=instance.email)
        if usr.username == instance.username:
            pass
        else:
            raise Exception('EmailExists')
    except User.DoesNotExist:
        pass
Tomasz Zielinski
Reply   •   6 楼
Tomasz Zielinski    12 年前

在此处添加:

User._meta.get_field_by_name('email')[0]._unique = True     

然后执行与此类似的SQL:

ALTER TABLE auth_user ADD UNIQUE (email);
bonidjukic
Reply   •   7 楼
bonidjukic    7 年前

自1.2版(2015年5月11日)以来,有一种方法可以使用设置选项动态导入任何选定的注册表单。 REGISTRATION_FORM .

所以,我们可以用这样的方法:

REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'

记录在案 here .

下面是链接到 changelog entry .

Arun
Reply   •   8 楼
Arun    9 年前

在models.py文件中添加以下函数。然后运行makemigrations和migrate。在Django1.7上测试

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()
2 revs, 2 users 96%<br/>user47
Reply   •   9 楼
2 revs, 2 users 96%<br/>user47    11 年前

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

使用习惯 validator :

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])
    #....
JB.
Reply   •   10 楼
JB.    11 年前

我认为正确的答案可以确保唯一性检查放在数据库中(而不是在django端)。因为由于时间和比赛条件,您可能会以数据库中的重复电子邮件结束,尽管例如 pre_save 这是正确的检查。

如果你真的非常需要这个,我想你可以尝试以下方法:

  1. 将用户模型复制到您自己的应用程序中,并将字段电子邮件更改为唯一的。
  2. 在管理应用程序中注册此用户模型(使用来自的管理类 django.contrib.auth.admin )
  3. 创建您自己的认证后端,使用您的模型而不是Django One。
Parag
Reply   •   11 楼
Parag    14 年前

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

Fernando Freitas Alves
Reply   •   12 楼
Fernando Freitas Alves    9 年前

Django有一个 Full Example 关于如何替换和使用自定义用户模型的文档,因此您可以添加字段并使用电子邮件作为用户名。

Nids Barthwal
Reply   •   13 楼
Nids Barthwal    5 年前

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

from django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
zVictor
Reply   •   14 楼
zVictor    13 年前

为确保用户(无论在何处)使用唯一的电子邮件进行保存,请将此添加到您的模型中:

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

请注意,这也确保了非空白电子邮件。然而,这并没有像适当的那样进行表单验证,只是引发了一个异常。

Alan Viars
Reply   •   15 楼
Alan Viars    12 年前

你的表格应该是这样的。

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
laz
Reply   •   16 楼
laz    6 年前

很神奇,但我找到了一个最好的解决方案!

Django注册 具有检查电子邮件字段唯一性的表单:RegistrationFormUniqueeMail

使用示例 here

jdavidls
Reply   •   17 楼
jdavidls    12 年前

在设置模块中:

# 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
eillarra
Reply   •   18 楼
eillarra    9 年前

用什么呢 unique_together 以一种“不同”的方式?到目前为止它对我有效。

class User(AbstractUser):
    ...
    class Meta(object):
        unique_together = ('email',)
Arne Babenhauserheide
Reply   •   19 楼
Arne Babenhauserheide    6 年前

警告: 下面的代码是为老版本的django编写的(之前 Custom User Models 介绍)。它包含一个竞赛条件,并且 只应与事务隔离级别一起使用 SERIALIZABLE 并请求范围内的事务。

因为字段实例的属性是只读的,所以代码无法工作。恐怕比你想象的要复杂一点。

如果只使用表单创建用户实例,则可以定义强制执行此行为的自定义模型表单:

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

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

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

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

更新

Django文档建议您使用 clean 用于跨多个窗体字段的所有验证的方法,因为在 <FIELD>.clean <FIELD>_clean 方法。这意味着您可以(主要)依赖字段的值 cleaned_data 从内 清洁的 .

因为表单域是按照声明的顺序进行验证的,所以我认为偶尔可以将多字段验证放在 <现场清洁 方法,只要相关字段出现在它所依赖的所有其他字段之后。我这样做是为了使任何验证错误都与字段本身相关,而不是与表单相关。