【问题标题】:Custom User model in django. UNIQUE constraint failed: users_user.usernamedjango 中的自定义用户模型。唯一约束失败:users_user.username
【发布时间】:2020-08-22 00:40:25
【问题描述】:

我正在尝试制作自定义注册表单。主要思想是用户应该使用电子邮件作为登录方法并且能够在配置文件中设置用户名(所以我不想覆盖用户名字段)。内置 django 用户模型的问题是用户名字段是必需的,所以我基于 AbstractUser 制作了自己的模型。现在,当我尝试注册新用户时,我得到“UNIQUE 约束失败:users_user.username”。

models.py

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

class User(AbstractUser):
    pass

forms.py

from django import forms
from .models import User

class RegisterForm(forms.ModelForm):
    username = forms.CharField(max_length=100, required=False)
    email = forms.EmailField(label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'email@example.com'}))
    password = forms.CharField(label='', max_length=100, widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

views.py

from django.shortcuts import render, redirect
from django.contrib import messages

from .forms import RegisterForm


def register(request):
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid(): 
            form.save()
            return redirect('trade')

    else:
        form = RegisterForm()
        return render(request, 'users/register.html', {'form': form})

AUTH_USER_MODEL = 'users.User' 已设置

我尝试在 models.py 中设置 email unique=True

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

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

现在我得到“视图 users.views.register 没有返回 HttpResponse 对象。它返回了 None”。

请记住,这是我自己的第一个 django 项目 :) 有帮助!

编辑解决方案:

好吧,我解决了这个问题。所有答案都在 django 文档中(谁愿意)。问题是,如果您像我一样是 python 和 django 的新手,阅读有关自定义用户模型的文档可能会非常不知所措。主要目标是将电子邮件设置为登录方法。为此,您必须在模型中设置 USERNAME_FIELD = 'email'。为了能够做到这一点,您必须使您的模型不是基于 AbstractUser,而是基于 AbstractBaseUser(https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-a-custom-user-model) 并重写您创建用户的方式。对我来说似乎很难,但 django 有一个非常好的示例,如何在文档末尾正确地做到这一点(https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#a-full-example)。我只是复制了代码,将 'date_of_birth' 替换为 'username' 并得到了我想要的内容以及一些了解在此之上的工作原理。

【问题讨论】:

    标签: python django


    【解决方案1】:

    关于错误"The view users.views.register didn't return an HttpResponse object. It returned None instead",这是因为register 没有在所有流中返回某些内容。在请求是POST 的情况下,第一个 if 语句为真,这就是我们所在的分支。如果表单有效,则一切正常,但如果不是,则不返回任何内容。我们不输入 else 部分,因为只有当请求不是 POST 时才会发生这种情况,您可以通过执行以下操作来修复它:

    def register(request):
        if request.method == 'POST':
            form = RegisterForm(request.POST)
            if form.is_valid(): 
                form.save()
                return redirect('trade')
    
        else:
            form = RegisterForm()
        return render(request, 'users/register.html', {'form': form})
    

    这样,在所有情况下你都会返回一些东西。

    关于原始错误。由于您继承自 AbstractUser,因此您继承了 username 字段以及与之相关的所有行为。特别是,它仍然需要是唯一的。 AbstractUser中是这样定义的:

        username = models.CharField(
            _('username'),
            max_length=150,
            unique=True,
            help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
            validators=[username_validator],
            error_messages={
                'unique': _("A user with that username already exists."),
            },
        )
    

    如果您向用户名提交空白值,这将给您带来麻烦。您的表单将允许它,但在数据库级别将不允许它。在那里我会覆盖用户名,只需添加如下内容:

        username = models.CharField(
            max_length=150,
            blank=True,
        )
    

    【讨论】:

    • 按照建议我添加了 username = models.CharField( max_length=150, blank=True, ) 现在当我尝试运行服务器或进行迁移时,我看到:“(auth.E003) 'User.username ' 必须是唯一的,因为它被命名为 'USERNAME_FIELD'。"我放弃并尝试设置 USERNAME_FIELD = email 并得到:“(auth.E002)自定义用户模型的名为'USERNAME_FIELD'的字段不得包含在'REQUIRED_FIELDS'中。”
    猜你喜欢
    • 2015-05-22
    • 2019-01-02
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    相关资源
    最近更新 更多