【问题标题】:django.db.utils.IntegrityError: FOREIGN KEY constraint failed in djangodjango.db.utils.IntegrityError: FOREIGN KEY 约束在 django 中失败
【发布时间】:2021-07-03 02:54:45
【问题描述】:

在使用邮递员创建用户时,我在创建新用户模型时不断收到上述错误 这是我的代码。

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.core.validators import RegexValidator
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from wallet.models import Transfer, Payment, Transaction, Wallet


class UserManager(BaseUserManager):
    use_in_migrations = True

    def create_user(self, name, phone, password,pin_code,confirm_pin,expected_delivery_month,email=None):
        user = self.model(name=name,phone=phone, email=email,pin_code=pin_code,confirm_pin=confirm_pin,
            expected_delivery_month=expected_delivery_month
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self,name,phone,password,pin_code,expected_delivery_month,email=None, ):
        user = self.create_user(name,phone,password,email,pin_code,expected_delivery_month)

        user.is_admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    name = models.CharField(max_length=120)
    phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$',
                                 message="Phone number must be entered in the format +256706626855. Up to 10 digits allowed.")
    phone = models.CharField('Phone', validators=[
                             phone_regex], max_length=17, unique=True, null=False)
    email = models.EmailField(
        verbose_name='email address', max_length=255, unique=True, null=True)
    is_admin = models.BooleanField(default=False)
    #now i need to add the pin coz its what am going to base on for the user creattion as the OTP
    pin_code = models.IntegerField(blank=False,unique=True)#vital here
    confirm_pin = models.IntegerField(blank=False)#this field here is to help in the confirmation of the pin

    expected_delivery_month = models.CharField(blank=False,default='january',max_length=20)
    objects = UserManager()

    USERNAME_FIELD = 'phone'
    REQUIRED_FIELDS = ['name','pin_code']

    
    def __str__(self):
        return self.name


    class Meta:
        unique_together = ("phone","pin_code")#since i need each phone number to have a unique pin code

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        return self.is_admin

    def has_perm(self,perm,obj=None):
        """Does the user have aspecific permission"""
        return True

    def has_module_perms(self,app_label):
        """Does the user have permissions to view thw app `app_label` """
        return True

@receiver(post_save, sender=User)
def create_wallet(sender, instance, **kwargs):
    """
        Create a wallet for every new user
    """
    Token.objects.create(user=instance)
    transfer = Transfer(
        transferred_to=instance, transferred_from=instance,transfer_reason='Initial Transfer',amount=0
    )
    transfer.save()
    transaction = Transaction(transfer_id=transfer,amount=transfer.amount)
    transaction.save()
    wallet = Wallet(balance=0, owner=instance, latest_transaction=transaction)
    wallet.save()


但是在使用 Postman 进行一些开发测试时,我不断收到以下错误。

 return self.connection.commit()
django.db.utils.IntegrityError: FOREIGN KEY constraint failed
[07/Apr/2021 09:19:04] "POST /user/register/%0A HTTP/1.1" 500 19194
Performing system checks...

我尝试通过在与用户模型相关的模型中添加 db_constraint=False 来进行一些更改,但仍然无效。以下是与用户模型具有 foreignKey rxnship 的模型。

import uuid
from django.conf import settings
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

# Create your models here.

class Payment(models.Model):
    Statuses = (
        ('PENDING', 'Pending'),
        ('COMPLETE', 'Complete'),
        ('FAILED', 'Failed'),
    )
    Categories = (
        ('TOP_UP','Top Up'),
        ('WITHDRAW','Withdraw')
    )
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,editable=False)
    status = models.CharField(max_length=2, choices=Statuses,default="PENDING")
    transaction_ref = models.UUIDField(default=uuid.uuid4)
    paid_at = models.DateTimeField(null=True)
    amount = models.IntegerField()
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING,db_constraint=False)
    category = models.CharField(max_length=2,choices=Categories,default="TOP_UP")

    def __str__(self) -> str:
        return str(self.id)

class Transfer(models.Model):
    id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
    transferred_to = models.ForeignKey(
        settings.AUTH_USER_MODEL,on_delete=models.DO_NOTHING,related_name='transferred_to',db_constraint=False)
    transferred_from = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING,related_name='transferred_from',db_constraint=False)
    amount = models.IntegerField()
    transfer_reason = models.CharField(max_length=200)

    def __str__(self) -> str:
        return str(self.id)

class Transaction(models.Model):
    id=models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    amount = models.IntegerField(editable=False)
    payment_id = models.ForeignKey(Payment,blank=True, on_delete=models.CASCADE, null=True)
    transfer_id = models.ForeignKey(Transfer, blank=True,null=True, on_delete=models.CASCADE)

    def __str__(self) -> str:
        return str(self.id)

class Wallet(models.Model):
    id=models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    balance = models.IntegerField()
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,db_constraint=False)
    latest_transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
    created_at = models.DateTimeField(default=timezone.now,editable=False)

    class Meta:
        ordering = ['created_at']

    def __str__(self) -> str:
        return str(self.id)

请注意,我在每个模型上添加了 db_constraint=False,并为用户模型添加了 ForeignKey rxnship。 注意:我使用我的用户模型作为自定义用户模型,并使用 sqlite3 作为我的数据库

这里是 postman 中的测试

{
    "name":"shifa",
    "phone":"0705674532",
    "pin_code":"2011",
    "confirm_pin":"2011",
    "expected_delivery_month":"December"
}

它是一个 post 请求并返回以下错误。

IntegrityError at /user/register/

FOREIGN KEY constraint failed

Request Method: POST
Request URL: http://127.0.0.1:8000/user/register/%0A
Django Version: 2.1
Python Executable: /home/utopia/pregweb/bin/python
Python Version: 3.6.8
Python Path: ['/home/utopia/pregweb/pregnew', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/utopia/pregweb/lib/python3.6/site-packages']
Server time: Wed, 7 Apr 2021 09:19:04 +0000
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework.authtoken',
 'rest_framework',
 'user',
 'wallet']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']


Traceback:

File "/home/utopia/pregweb/lib/python3.6/site-packages/django/db/backends/base/base.py" in _commit
  239.                 return self.connection.commit()

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:

【问题讨论】:

  • 您能否运行代码并检查失败的对象创建,尝试在post_save 方法中添加打印语句。
  • The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception: 那么下面的异常是什么?

标签: python django sqlite django-rest-framework postman


【解决方案1】:

尝试创建一个像(信号部分)这样的交易:

transaction = Transaction(transfer_id=transfer.id,amount=transfer.amount)

我已添加id 转移。

【讨论】:

  • transfer_id 是一个 FK 字段,因此 Django 需要一个对象,而不是 id
  • 已在我的块中添加了with transaction.atomic(),但仍然出现错误
【解决方案2】:

这里至少有两个问题。

首先,如果您一次创建几个 DB 实体,则需要将此块包装在 transaction.atomic 中。

第二,这个模型。

class Transaction(models.Model):
    id=models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    amount = models.IntegerField(editable=False)
    payment_id = models.ForeignKey(Payment,blank=True, on_delete=models.CASCADE, null=True)
    transfer_id = models.ForeignKey(Transfer, blank=True,null=True, on_delete=models.CASCADE)

对于PaymentTransfer 具有可为空的fk。

这就是你创建它的方式

transfer = Transfer(
        transferred_to=instance, transferred_from=instance,transfer_reason='Initial Transfer',amount=0
    )
    transfer.save()

因此,您要么需要在这些字段上添加 default=None 并运行迁移,要么在创建时传递 None

第三,不要在你的模型中添加entity_id。如果你创建

 transfer = models.ForeignKey(Transfer...

Django 会自动在您的模型上添加transfer_id,这就是数据库中的内容。

docs

在幕后,Django 将“_id”附加到字段名称以创建其数据库列名称。在上面的示例中,汽车模型的数据库表将有一个manufacturer_id 列。 (您可以通过指定 db_column 显式更改它)但是,您的代码永远不必处理数据库列名,除非您编写自定义 SQL。您将始终处理模型对象的字段名称。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 2022-10-17
    相关资源
    最近更新 更多