Ошибка формы Django: django.db.utils.IntegrityError: UNIQUE constraint failed: legal_useragreedtolegal.user_id

Когда я вызываю 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

Я думаю, это может быть потому, что у меня есть OneToOneField и Django пытается сохранить в UserAgreedToLegal и User Model, но модель User уже имеет этот ID, поэтому уникальное ограничение не работает, но не уверен.

Вы правы, OneToOneField по сути является ForeignKey с unique=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 должны указывать на представление, которое будет рендерить эту страницу.

Причина, по которой он не срабатывал, заключалась в том, что существовало отношение "один к одному" с моделью пользователя django, и когда я вызывал form.save(), он пытался сохранить новую строку (вставить нового пользователя) как в User, так и в мою модель, а затем он видел, что этот user_id уже существует в моей модели, и он говорил мне, что это невозможно сделать, потому что тогда это нарушало бы правило, которое я установил, о наличии только отношения "один к одному", потому что если бы он сохранил каждого пользователя, у него было бы много записей. Это создаст отношения один ко многим вместо отношений один к одному.

Вместо этого мне нужно было сказать django, что я не хочу вставлять новую запись в мою модель, или обновить ее, если такая запись уже существует, а если нет, то создать ее, сохраняя связь с моделью User.

Мне нужно было передать экземпляр, чтобы 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()
Вернуться на верх