Django 测试在数据库中找不到它创建的对象的 id

问题描述 投票:0回答:1

上下文

我正在建立一个电子商务,它有几个应用程序,如帐户、产品、类别、评论等。

我得到的错误输出是这样的:

django.db.utils.IntegrityError: insert or update on table "products_product" violates foreign key constraint "products_product_category_id_9b594869_fk_categories_category_id"
DETAIL:  Key (category_id)=(3) is not present in table "categories_category".

当 Django 到达特定测试显示输出时,类别 ID 应该是 4,因为类别模型的其他三个实例是为之前的测试创建的。

只有我按特定顺序运行测试才能通过测试。

守则

产品型号

from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=128)
    brand = models.CharField(max_length=128)
    image_url = models.CharField(default='',
                             max_length=512,
                             null=True,
                             blank=True)
    description = models.CharField(max_length=512)
    specifications = models.JSONField(null=True, blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    vendor = models.ForeignKey('accounts.User',
                               on_delete=models.PROTECT,
                               related_name='products')
    category = models.ForeignKey('categories.Category',
                                 on_delete=models.PROTECT,
                                 related_name='products',
                                 blank=True,
                                 null=True)
    available = models.BooleanField(default=True)

    class Meta:
        unique_together = ['vendor', 'name']

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

产品模型测试

from django.test import TestCase

from products.models import Product

from products.tests.helpers import create_product


class SetUp(TestCase):

    def setUp(self):
        self.product = create_product()
        return super().setUp()


class TesteProduct(SetUp):

    def test_product(self):
        self.assertEqual(
            Product.objects.filter(pk=self.product.pk).exists(),
            True,
        )
        retrieved_product = Product.objects.get(pk=self.product.pk)
        self.assertEqual(
            retrieved_product.name,
            self.product.name,
        )
        self.assertEqual(
            retrieved_product.brand,
            self.product.brand,
        )
        self.assertEqual(
            retrieved_product.description,
            self.product.description,
        )
        self.assertEqual(
            retrieved_product.specifications,
            self.product.specifications,
        )
        self.assertEqual(
            retrieved_product.category,
            self.product.category,
        )

products
应用程序的端点测试

from json import dumps

from django.urls import reverse
from django.test import TestCase

from rest_framework import status
from rest_framework.request import Request
from rest_framework.test import APIRequestFactory, APIClient

from accounts.tests.helpers import UserTestMixin

from categories.tests.helpers import create_category

from products.models import Product
from products.tests.data import product_data
from products.tests.helpers import create_products_list
from products.api.serializers import ProductSerializer


class SetUpTestCase(UserTestMixin, TestCase):

    def setUp(self):
        self.category = create_category()
        self.vendor = self.create_vendor()

        product_data['vendor'] = self.vendor
        product_data['specifications'] = dumps(
            product_data['specifications']
        )
        product_data['category_id'] = self.category.pk

        factory = APIRequestFactory()
        self.request = Request(factory.get('/'))

        self.client = APIClient()
        self.client.force_authenticate(user=self.vendor)
        return super().setUp()


class ProductListEndpointTestCase(SetUpTestCase):

    def test_post(self):
        response = self.client.post(reverse('products'),
                                    data=product_data)
        serializer = ProductSerializer(
            Product.objects.get(pk=response.data['id']),
            context={'request': self.request}
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data, serializer.data)
        self.assertEqual(Product.objects.count(), 1)

    def test_get(self):
        create_products_list(self.vendor, self.category)
        response = self.client.get(reverse('products'))
        serializer = ProductSerializer(Product.objects.all(),
                                       many=True,
                                       context={'request': self.request})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data, serializer.data)
        self.assertTrue(Product.objects.count() > 1)

审查模型

from django.db import models


class Review(models.Model):
    """
    Reviews require the order that the product was ordered in
    Args:
        - order (Order): The order that the product to review was was ordered in
        - product (Product): The product to review
        - user (User): The user that made the review
    """
    order = models.ForeignKey('orders.Order',
                               on_delete=models.PROTECT,
                               related_name='reviews')
    product = models.ForeignKey('products.Product',
                                 on_delete=models.PROTECT,
                                 related_name='reviews')
    user = models.ForeignKey('accounts.User',
                             on_delete=models.PROTECT,
                             related_name='reviews')
    title = models.CharField(max_length=64)
    text = models.CharField(max_length=2048)
    rating = models.IntegerField()
    date = models.DateField(auto_now=True)

    class Meta:
        """ Users can only review a product once (per order) """
        unique_together = ['order', 'product']

    def __str__(self) -> str:
        return self.text[:100]

审查模型的测试

from django.test import TestCase

from reviews.models import Review
from reviews.tests.helpers import create_review


class SetUpTestCase(TestCase):

    def setUp(self):
        self.review = create_review()
        return super().setUp()


class TestReview(SetUpTestCase):

    def test_review(self):
        self.assertEqual(
            Review.objects.filter(pk=self.review.pk).exists(),
            True,
        )
        retrived_review = Review.objects.get(pk=self.review.pk)
        self.assertEqual(
            retrived_review.product,
            self.review.product,
        )
        self.assertEqual(
            retrived_review.user,
            self.review.user,
        )
        self.assertEqual(
            retrived_review.title,
            self.review.title,
        )
        self.assertEqual(
            retrived_review.text,
            self.review.text,
        )
        self.assertEqual(
            retrived_review.rating,
            self.review.rating,
        )
        self.assertEqual(
            retrived_review.date,
            self.review.date,
        )

测试中使用的助手

产品帮手

from products.models import Product

from accounts.tests.helpers import UserTestMixin

from inventory.tests.helpers import create_inventory_item

from categories.tests.helpers import create_category

from products.tests.data import (
    product_data, product_data_list
)


def create_product(vendor=None, category=None, data=product_data,
                   append_to_inventory=True):

    data['vendor'] = vendor or UserTestMixin().create_vendor()
    data['category'] = category or create_category()

    product = Product.objects.create(**data)
    if append_to_inventory:
        add_product_to_inventory(product, quantity=10)
    return product

def create_products_list(vendor=None, category=None, data=product_data_list):
    return [
        create_product(vendor, category, product_data) for product_data in data
    ]

def add_product_to_inventory(product, quantity=1):
    return create_inventory_item(product, quantity)


评论助手

from accounts.tests.helpers import UserTestMixin

from products.tests.helpers import create_product

from orders.tests.helpers import create_order, create_order_item

from reviews.models import Review
from reviews.tests.data import review_data


def create_review(user=None, product=None, review_data=review_data):
    customer = user or UserTestMixin().create_customer()
    order = create_order(user=customer)
    product = product or create_product()
    create_order_item(product=product, order=order)
    return Review.objects.create(
        user = customer,
        order = order,
        product = product,
        **review_data,
    )

注意:我知道有很多东西遗漏了,但请随意询问您是否需要有关该项目的更多信息。

我还有几个测试,但是同时运行这三个测试,导致了问题。

如果按此顺序运行测试...

python manage.py test reviews products

都通过了!

以默认顺序运行时...

python manage.py test products reviews

我收到之前提到的错误。

django.db.utils.IntegrityError: insert or update on table "products_product" violates foreign key constraint "products_product_category_id_9b594869_fk_categories_category_id"
DETAIL:  Key (category_id)=(3) is not present in table "categories_category".

我确认模型上的所有更改都适用于数据库,我也在新数据库中尝试。

我以不同的顺序运行测试,显然,Django 尝试创建产品的类别的 ID 始终是实际 ID - 1.

我在一个用 pipenv 创建的 venv 中运行我的 Django 项目,还有其他包

  • Django 4.2
  • Python 3.10
  • Psycopg-3.1.8(二进制)
django testing django-models django-rest-framework django-testing
1个回答
0
投票

我是初学者,我可能是错的我认为发生此错误是因为两个表都有关系。所以一个依赖于另一个所以依赖表列(带有forienkey)必须具有具有主键constaint

的表列的值
© www.soinside.com 2019 - 2024. All rights reserved.