Django IntegrityError UNIQUE约束失败,即使尝试登录到管理面板

6l7fqoea  于 2023-06-07  发布在  Go
关注(0)|答案(2)|浏览(254)

我已经搜索了类似的主题,但没有找到一个解决方案,为我的特定情况。我有一个User扩展模型,另外还有UserProfile来扩展和存储一些用户信息。UserProfileUser模型有 * OneToOne * 关系。我有一个User模型save方法被覆盖,以立即在User对象上创建一个UserProfile对象。但是每当我创建一个新的User示例**IntegrityError UNIQUE constraint failed: accounts_userprofile.user_id时,即使两个示例(User和UserProfile)都成功创建,也会引发。在创建用户(甚至是超级用户)后,每当我尝试登录Django Admin时,我都得到相同的IntegrityError UNIQUE constraint failed: accounts_userprofile.user_id**。

我试过

1.应用迁移(以防万一);
1.完全删除数据库,从头开始重复所有内容;
我知道有一种方法可以将OneToOne关系更改为ForeignKey,但如果有其他解决方案,我希望保留这种关系。

models.py:

class UserManager(BaseUserManager):
def create_user(self, email, password, **kwargs):
    if not email:
        raise ValueError("Please, provide a correct email.")
    email = self.normalize_email(email)
    user = self.model(email=email, **kwargs)
    user.set_password(password)
    user.save()
    return user

def create_superuser(self, email, password, **kwargs):
    kwargs.setdefault('is_staff', True)
    kwargs.setdefault('is_superuser', True)
    kwargs.setdefault('is_active', True)

    if not kwargs.get('is_staff'):
        raise ValueError("Superuser must have 'is_staff' value set to True")

    if not kwargs.get('is_superuser'):
        raise ValueError("Superuser must have 'is_superuser' value set to True")

    if not kwargs.get('is_active'):
        raise ValueError("Superuser must have 'is_active' value set to True")
    return self.create_user(email, password, **kwargs)

class User(AbstractBaseUser, PermissionsMixin):

    """ Custom user model """

    objects = UserManager()

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.EmailField(max_length=255, unique=True)
    password = models.CharField(max_length=128, null=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    USERNAME_FIELD = "email"

    def save(self, *args, **kwargs):
        super(User, self).save(*args, **kwargs)
        UserProfile.objects.create(user=self)

class UserProfile(models.Model):

    GENDER_CHOICES = (
        ('male', 'Male'),
        ('female', 'Female')
    )

    first_name = models.CharField(max_length=250, null=True, blank=True)
    last_name = models.CharField(max_length=250, null=True, blank=True)
    gender = models.CharField(max_length=10, choices=GENDER_CHOICES, null=True, blank=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')

serializers.py

class UserSerializer(serializers.ModelSerializer):

    password = serializers.CharField(
        write_only=True,
        required=True
    )

    class Meta:
        model = get_user_model()
        fields = (
            "id",
            "password",
            "email",
            "profile_link",
            "created_at",
            "updated_at"
        )

class UserProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserProfile
        fields = "__all__"

我不明白为什么在登录到管理面板时代码**UserProfile.objects.create(user=self)**上的这一行出现错误。为什么登录时一直执行save方法?

更新:

如果我删除分配给用户尝试登录的UserProfile对象,则不会出现IntegrityError。

btqmn9zl

btqmn9zl1#

因为当你登录时,Django会更新last_login字段并运行保存方法。在这种情况下,UserProfile创建行将引发错误。
我的建议是不要在保存方法上创建UserProfile,你可以为那个signals使用create信号
如果你想使用你的方式,你可以使用get_or_create

velaa5lx

velaa5lx2#

因为当你登录时,Django会更新last_login字段并运行保存方法。在这种情况下,UserProfile创建行将引发错误。
我的建议是不要在保存方法上创建UserProfile,你可以为那个信号使用create signal
如果你想使用你的方式,你可以使用get_or_create
如果您更喜欢使用get_or_create,这将很好地工作,但这也会在每次登录时触发不必要的查询。
我会考虑用它来做一个小小的改进:

def save(self, *args, **kwargs):
        is_create = not self.pk
        super(User, self).save(*args, **kwargs)
        if is_create:
            UserProfile.objects.create(user=self)

相关问题