【问题标题】:Django form error: django.db.utils.IntegrityError: UNIQUE constraint failed: legal_useragreedtolegal.user_idDjango 表单错误:django.db.utils.IntegrityError:唯一约束失败:legal_useragreedtolegal.user_id
【发布时间】:2022-01-21 09:25:42
【问题描述】:

每当我调用 form.save() 时,我都会收到“django.db.utils.IntegrityError: UNIQUE constraint failed: legal_useragreedtolegal.user_id

我认为这可能是因为我有一个 oneToOneField 并且 Django 正在尝试保存到 UserAgreedToLegal 和 User Model 但 User 模型已经具有该 ID,因此唯一约束失败,但不确定。

我想知道如何解决这个问题。我在下面列出了我的模型、表单和视图代码

models.py

import uuid

from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone as django_timezone


class UserAgreedToLegal(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    agreed_first_terms_of_service = models.BooleanField(default=False, blank=False, null=False)
    date_agreed = models.DateField(null=True, default=django_timezone.now)
    uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)

    def __str__(self):
        return self.user.username

forms.py

from django import forms

from legal.models import UserAgreedToLegal


class TermsOfServiceAgreementForm(forms.ModelForm):
    class Meta:
        model = UserAgreedToLegal
        fields = [
            'agreed_first_terms_of_service'
        ]

views.py

    if request.method == 'POST':
        form = TermsOfServiceAgreementForm(request.POST)
        if form.is_valid():
            form.clean()
            terms_of_service_agreement = form.save(commit=False)
            terms_of_service_agreement.user = request.user

            terms_of_service_agreement.save()

结果是

django.db.utils.IntegrityError: UNIQUE constraint failed: legal_useragreedtolegal.user_id

【问题讨论】:

  • A OneToOneField 表示同一用户不能有两个或多个UserAgreedToLegals。

标签: python django django-forms


【解决方案1】:

我认为这可能是因为我有一个 OneToOneField 并且 Django 正在尝试保存到 UserAgreedToLegal 和 User Model 但 User 模型已经具有该 ID,因此唯一约束失败,但不确定。

你是对的,OneToOneField 本质上是ForeignKeyunique=True。因此,第二次访问此视图是没有意义的。

您可以检查该人是否已经同意法律条款,如果是,则重定向到页面,例如呈现页面以说明用户已经同意的视图,例如:

from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect

@login_required
def my_view(request):
    if UserAgreedToLegal.objects.filter(user=request.user).exists():
        return redirect('name-of-some-view')
    if request.method == 'POST':
        # …
    # …

name-of-some-view 应该指向将呈现该页面的视图。

【讨论】:

  • 我不会重新审视这个观点。这是用户第一次访问此视图
  • @AugustusCaesar:@AugustusCaesar:UserAgreedToLegal 是为那个用户而存在的,不是在那个视图中,而是另一个视图或信号创建了UserAgreedToLegal 对象。
【解决方案2】:

它失败的原因是因为与 django 用户模型存在 OneToOne 关系,当我调用 form.save() 时,它试图将新行(插入新用户)保存到用户和我的模型中然后它会看到这个 user_id 已经存在于我的模型中,它会告诉我它无法完成,因为那样它会违反我放置的只有一对一关系的规则,因为如果它确实保存了每个用户将有很多记录。这将创建一对多而不是一对一。

相反,我需要做的是告诉 django 我不想在我的模型中插入新记录,或者如果该记录已经存在则更新它,如果不创建它,同时保持与用户的关系型号。

我必须为 Django Forms 传递一个实例,才能知道我已经有了这个模型并且我不想更新这个实例。

这是对我有用的代码


if request.method == 'POST':
    my_user = UserAgreedToLegal.objects.get_or_create(user=request.user)[0]
    form = TermsOfServiceAgreementForm(request.POST, instance=my_user)

    if form.is_valid():
        form.clean()
        terms = form.save(commit=False)
        terms.user = request.user
        terms.save()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-05
    • 2016-04-11
    • 2019-12-31
    • 1970-01-01
    • 2022-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多