Django 测试:Postgres 上的 setUpTestData 抛出:“重复的键值违反了唯一约束”

2024-03-22

我在单元测试中遇到数据库问题。我认为这与我使用 TestCase 和 setUpData 的方式有关。

当我尝试使用某些值设置测试数据时,测试会抛出以下错误:

django.db.utils.IntegrityError: duplicate key value violates unique constraint 

...

psycopg2.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_productgroup_product_name_48ec6f8d_uniq"
DETAIL:  Key (product_name)=(Almonds) already exists.

我更改了所有主键,它似乎运行良好。它似乎不会影响任何测试。

但是,我担心我做错了什么。当它第一次发生时,我在我的应用程序上逆转了大约一个小时的工作(对于菜鸟来说没有那么多代码),这纠正了问题。

然后,当我写回更改时,同样的问题再次出现。下面粘贴了测试用例。该问题似乎是在我添加 sortrecord 项目后发生的,但与其上面的项目相对应。

我不想在测试中继续检查和更改主键和 url,因此如果有人发现我使用此方法的方式有问题,请帮助我。谢谢!

TestCase

class DetailsPageTest(TestCase):


@classmethod
def setUpTestData(cls):

    cls.product1 = ProductGroup.objects.create(
                        product_name="Almonds"
                        )
    cls.variety1 = Variety.objects.create(
                        product_group = cls.product1,
                        variety_name = "non pareil",
                        husked = False,
                        finished = False,
                        )

    cls.supplier1 = Supplier.objects.create(
                        company_name = "Acme",
                        company_location = "Acme Acres",
                        contact_info = "Call me!"
                        )

    cls.shipment1 = Purchase.objects.create(
                        tag=9,
                        shipment_id=9999,
                        supplier_id = cls.supplier1,
                        purchase_date='2015-01-09',
                        purchase_price=9.99,
                        product_name=cls.variety1,
                        pieces=99,
                        kgs=999,
                        crackout_estimate=99.9
                        )
    cls.shipment2 = Purchase.objects.create(
                        tag=8,
                        shipment_id=8888,
                        supplier_id=cls.supplier1,
                        purchase_date='2015-01-08',
                        purchase_price=8.88,
                        product_name=cls.variety1,
                        pieces=88,
                        kgs=888,
                        crackout_estimate=88.8
                        )
    cls.shipment3 = Purchase.objects.create(
                        tag=7,
                        shipment_id=7777,
                        supplier_id=cls.supplier1,
                        purchase_date='2014-01-07',
                        purchase_price=7.77,
                        product_name=cls.variety1,
                        pieces=77,
                        kgs=777,
                        crackout_estimate=77.7
                        )

    cls.sortrecord1 = SortingRecords.objects.create(
                        tag=cls.shipment1,
                        date="2015-02-05",
                        bags_sorted=20,
                        turnout=199,
                        )

    cls.sortrecord2 = SortingRecords.objects.create(
                        tag=cls.shipment1,
                        date="2015-02-07",
                        bags_sorted=40,
                        turnout=399,
                        )
    cls.sortrecord3 = SortingRecords.objects.create(
                        tag=cls.shipment1,
                        date='2015-02-09',
                        bags_sorted=30,
                        turnout=299,
                        )

Models

from datetime import datetime

from django.db import models
from django.db.models import Q


class ProductGroup(models.Model):
    product_name = models.CharField(max_length=140, primary_key=True)

    def __str__(self):
        return self.product_name

    class Meta:
        verbose_name = "Product"

class Supplier(models.Model):
    company_name = models.CharField(max_length=45)
    company_location = models.CharField(max_length=45)
    contact_info = models.CharField(max_length=256)

    class Meta:
        ordering = ["company_name"]

    def __str__(self):
        return self.company_name

class Variety(models.Model):
    product_group = models.ForeignKey(ProductGroup)
    variety_name = models.CharField(max_length=140)
    husked = models.BooleanField()
    finished = models.BooleanField()
    description = models.CharField(max_length=500, blank=True)

    class Meta:
        ordering = ["product_group_id"]
        verbose_name_plural = "Varieties"

    def __str__(self):
        return self.variety_name


class PurchaseYears(models.Manager):

    def purchase_years_list(self):
        unique_years = Purchase.objects.dates('purchase_date', 'year')
        results_list = []
        for p in unique_years:
            results_list.append(p.year)
        return results_list


class Purchase(models.Model):
    tag = models.IntegerField(primary_key=True)
    product_name = models.ForeignKey(Variety, related_name='purchases')
    shipment_id = models.CharField(max_length=24)
    supplier_id = models.ForeignKey(Supplier)
    purchase_date = models.DateField()
    estimated_delivery = models.DateField(null=True, blank=True)
    purchase_price = models.DecimalField(max_digits=6, decimal_places=3)
    pieces = models.IntegerField()
    kgs = models.IntegerField()
    crackout_estimate = models.DecimalField(max_digits=6,decimal_places=3, null=True)
    crackout_actual = models.DecimalField(max_digits=6,decimal_places=3, null=True)
    objects = models.Manager()
    purchase_years = PurchaseYears()
    # Keep manager as "objects" in case admin, etc. needs it. Filter can be called like so:
    # Purchase.objects.purchase_years_list()
    # Managers in docs: https://docs.djangoproject.com/en/1.8/intro/tutorial01/

    class Meta:
        ordering = ["purchase_date"]

    def __str__(self):
        return self.shipment_id

    def _weight_conversion(self):
        return round(self.kgs * 2.20462)
    lbs = property(_weight_conversion)

class SortingModelsBagsCalulator(models.Manager):

    def total_sorted(self, record_date, current_set):
        sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if
                  SortingRecords['date'] <= record_date]
        return sum(sorted)


class SortingRecords(models.Model):
    tag = models.ForeignKey(Purchase, related_name='sorting_record')
    date = models.DateField()
    bags_sorted = models.IntegerField()
    turnout = models.IntegerField()
    objects = models.Manager()

    def __str__(self):
        return "%s  [%s]" % (self.date, self.tag.tag)

    class Meta:
        ordering = ["date"]
        verbose_name_plural = "Sorting Records"

    def _calculate_kgs_sorted(self):
        kg_per_bag = self.tag.kgs / self.tag.pieces
        kgs_sorted = kg_per_bag * self.bags_sorted
        return (round(kgs_sorted, 2))
    kgs_sorted = property(_calculate_kgs_sorted)

    def _byproduct(self):
        waste = self.kgs_sorted - self.turnout
        return  (round(waste, 2))
    byproduct = property(_byproduct)

    def _bags_remaining(self):
        current_set = SortingRecords.objects.values().filter(~Q(id=self.id), tag=self.tag)
        sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if
                  SortingRecords['date'] <= self.date]
        remaining = self.tag.pieces - sum(sorted) - self.bags_sorted
        return remaining
    bags_remaining = property(_bags_remaining)

EDIT

它对于整数也会失败,就像这样。

django.db.utils.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_purchase_pkey"
DETAIL:  Key (tag)=(9) already exists.

UDPATE

所以我应该早点提到这一点,但我完全忘记了。我有两个使用相同数据的单元测试文件。只是为了好玩,我在两个实例中都匹配了主键setUpTestData()到不同的值,果然,我得到了同样的错误。

在我向其中之一添加更多数据之前,这两个设置并排工作得很好。现在看来,他们需要不同的价值观。我想你只能在这么长时间内使用重复数据。


几个月来我偶尔遇到这个问题。我相信我刚刚找到了根本原因和几个解决方案。

Summary无论出于何种原因,Django 测试用例基类似乎没有删除由我们调用它创建的数据库记录TestCase1跑步前TestCase2。其中,在TestCase2当它尝试使用与以下相同的 ID 在数据库中创建记录时TestCase1数据库提出了一个DuplicateKey异常,因为这些 ID 已存在于数据库中。即使说“请”这个神奇的词也无助于解决数据库重复键错误。

好消息是,有多种方法可以解决这个问题!这里有几个...

解决方案1

确保您是否重写了类方法tearDownClass你所说的super().tearDownClass()。如果你覆盖tearDownClass()如果不调用它的 super,它又永远不会调用TransactionTestCase._post_teardown() nor TransactionTestCase._fixture_teardown()。引用 TransactionTestCase._post_teardown()` 中的文档字符串:

    def _post_teardown(self):
        """
        Perform post-test things:
        * Flush the contents of the database to leave a clean slate. If the
          class has an 'available_apps' attribute, don't fire post_migrate.
        * Force-close the connection so the next test gets a clean cursor.
        """

If TestCase.tearDownClass()不是通过调用super()那么数据库不会在测试用例之间重置,您将得到可怕的重复键异常。

解决方案2

覆盖TransactionTestCase并设置类变量serialized_rollback = True, 像这样:

class MyTestCase(TransactionTestCase):
    fixtures = ['test-data.json']
    serialized_rollback = True

    def test_name_goes_here(self):
        pass

引用来源:

class TransactionTestCase(SimpleTestCase):

    ...

    # If transactions aren't available, Django will serialize the database
    # contents into a fixture during setup and flush and reload them
    # during teardown (as flush does not restore data from migrations).
    # This can be slow; this flag allows enabling on a per-case basis.
    serialized_rollback = False

When serialized_rollback被设定为True,Django 测试运行程序会回滚测试用例之间插入数据库的任何事务。 Batta bing、batta bang...不再有重复的按键错误!

结论

可能还有很多方法可以实现OP问题的解决方案,但这两种方法应该可以很好地工作。为了清楚起见并更深入地了解底层 Django 测试用例基类,肯定希望其他人添加更多解决方案。唷,最后一句话快说三遍,你就可以赢得一匹小马!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django 测试:Postgres 上的 setUpTestData 抛出:“重复的键值违反了唯一约束” 的相关文章

随机推荐

  • HDFS如何计算可用块?

    假设块大小为 128MB 则集群有 10GB 因此大约 80 个可用块 假设我创建了 10 个小文件 这些文件总共占用磁盘上 128MB 块文件 校验和 复制 和 10 个 HDFS 块 如果我想向HDFS添加另一个小文件 那么HDFS使用
  • 谷歌地图API可以进行语音导航吗?

    如何使用 google 地图 api v3 激活基于语音的方向 我已经实现了给出从起点到终点的方向的地图 但现在我想听听我当前所在位置的名称 请帮忙 我在 ios UIWebView 中实现了它 所以我从 GPS 获取当前位置 现在我每 2
  • JavaScript - for循环问题中变量递增

    我试图创建一个 for 循环 递增数字 1 4 并打印它们 但是当我在循环后打印 i 的值时 我的代码输出 5 for i 1 i lt 5 i document write i br Outputs numbers 1 4 documen
  • Kinect 1.8 颜色帧和深度帧不协调

    我的程序存在深度和彩色图像之间协调不佳的问题 玩家面具与人物不在同一位置 见下图 void AllFreamReady object sender AllFramesReadyEventArgs e using ColorImageFram
  • 等待 5 秒再执行下一行

    下面这个函数并没有像我想要的那样工作 作为一个 JS 新手 我不明白为什么 我需要它等待 5 秒钟 然后再检查是否newState is 1 目前 它不会等待 而是立即检查 function stateChange newState set
  • 将 zip 文件导入为库 - Eclipse Java

    我在导入 google http 库时陷入困境 我在链接中做了一些研究 例如 Eclipse Java 如何导入 zip 格式的库 https stackoverflow com questions 14375810 eclipse jav
  • 将 Java 对象转换为 Java Map

    我在用org eclipse jetty util ajax JSON解析 JSON 文本 但是JSON parse 字符串 方法生成一个对象 我需要它作为映射 在内部 它正是所提到的类的对象 但是 如何在不构造新对象或收到未经检查的转换警
  • 如何配置 Webpack 开发服务器来为特定文件夹提供服务,同时通过不同的服务器运行站点的其余部分?

    一些简单的背景知识 我公司的站点运行 CMS 并由 CMS 处理所有路由 没有 html 文件 只有 razor 文件 cshtml 虽然我更愿意从头开始重做网站 但这不是一个选择 因此我尝试通过将 vue js 与 webpack 开发工
  • gcc *有时*以一种奇怪的方式解决重载歧义

    在回答之前 这不是一个关于如何让这段代码做我想做的事情的问题 我已经知道该怎么做 参见这个问题的结尾 这是一个关于理解编译器为什么要做它所做的事情的问题 请考虑以下 简化的 代码 include
  • Javascript:带有尾随字符的 parseInt()

    parseInt 7em 10 回报7在我测试过的所有浏览器中 但我可以依靠这个吗 我问的原因是 我想根据 em 执行一些计算 例如 elem1 style top uses em units elem2 style top parseIn
  • 什么是“准实施”?

    有时 在搜索会员的推荐信时 我会收到此弹出窗口 这通常需要很长时间 所以我倾向于取消 但我想知道 我错过了什么 什么是 准实施 根据resharper 支持的这个答案 https resharper support jetbrains co
  • 读取 RDS AWS 中的副本

    我是亚马逊 RDS 的新手 我已经在RDS中设置了一个数据库实例 我想尝试 RDS 只读副本功能 我有几个疑问 只读副本适合什么样的应用 只读副本将数据同步还是异步复制到其他只读副本 它是多可用区部署的替代品吗 与MYSQL中的主从或主主复
  • Javascript 中的 try-catch 语句可以捕获哪些类型的错误?

    如果我写 try null foobar catch e alert e 没有任何警报 但ReferenceError已登录到控制台 然而 try barfoo foobar catch e alert e 显示带有以下内容的警报Refer
  • 如何从Windows任务管理器检测程序java强制关闭?

    如果我问了这样一个菜鸟问题冒犯了某人 大家很抱歉 因为我看到有人因不恰当而 标记了 问题 这是我第一次在这里提问 所以如果有什么不合适的地方请原谅我 如果我的英语不是很好 请原谅 当我的程序通过任务管理器关闭时 我试图创建一个临时文件 但我
  • 将大型数据集加载到 R 中的最快方法和最快格式是什么[重复]

    这个问题在这里已经有答案了 我有一个很大的数据集 未压缩时大约 13GB 我需要重复加载它 第一次加载 并保存为不同的格式 可能非常慢 但此后的每次加载都应该尽可能快 加载数据集的最快方式和最快格式是什么 我怀疑最佳选择是这样的 saveR
  • Yang 的 XPath current()

    这是我的后续问题Yang 中的 Xpath current https stackoverflow com questions 55888566 xpath current in yang经过前面的讨论 我为 libxml2 实现了一个自定
  • 批处理、重复和洗牌对 TensorFlow 数据集有什么作用?

    我目前正在学习 TensorFlow 但我在下面的代码片段中遇到了困惑 dataset dataset shuffle buffer size 10 batch size dataset dataset repeat num epochs
  • 使用 ServiceRoute 时指定 WCF 绑定

    我目前正在使用以下代码注册 WCF 服务 var factory new DefaultServiceHostFactory RouteTable Routes Add new ServiceRoute XXXEndPoint factor
  • 在框中显示 html 代码,如 yahoo html 消息

    我想查看框中的用户 html 代码 例如 Gmail Yahoo html 消息 我将在诸如邮寄我的旧代码之类的事情中使用代码 我认为我太愚蠢了 div class mydiv style border 1px 000 solid THE
  • Django 测试:Postgres 上的 setUpTestData 抛出:“重复的键值违反了唯一约束”

    我在单元测试中遇到数据库问题 我认为这与我使用 TestCase 和 setUpData 的方式有关 当我尝试使用某些值设置测试数据时 测试会抛出以下错误 django db utils IntegrityError duplicate k