簡體   English   中英

django.db.utils.IntegrityError: FOREIGN KEY 約束在 django 中失敗

[英]django.db.utils.IntegrityError: FOREIGN KEY constraint failed in django

在使用 postman 創建用戶時,我在創建新用戶 model 時不斷收到上述錯誤,這是我的代碼。

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...

我嘗試通過在與用戶 model 相關的模型中添加 db_constraint=False 來進行一些更改,但仍然徒勞無功。以下是用戶 model 具有外鍵 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 我在每個 model 上添加了一個 ForeignKey rxnship 給用戶 model。 注意:我使用我的用戶 model 作為自定義用戶 model,並使用 sqlite3 作為我的數據庫

這是 postman 中的測試

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

它是一個發布請求並返回以下錯誤。

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:

嘗試創建一個事務,如(信號部分):

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

我已添加id以進行轉移。

這里至少有兩個問題。

首先,如果您一次創建幾個數據庫實體,則需要將此塊包裝在transaction.atomic中。

二、這個model。

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

第三,不要在 model 中添加entity_id 如果你創建

 transfer = models.ForeignKey(Transfer...

Django 將自動在您的 model 上添加transfer_id ,這就是數據庫中的內容。

文檔

在幕后,Django 將“_id”附加到字段名稱以創建其數據庫列名稱。 在上面的示例中,Car model 的數據庫表將有一個manufacturer_id 列。 (您可以通過指定 db_column 顯式更改此設置)但是,您的代碼永遠不必處理數據庫列名,除非您編寫自定義 SQL。 您將始終處理 model object 的字段名稱。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM