django update_or_create 获取“重复键值违反唯一约束"; [英] django update_or_create gets "duplicate key value violates unique constraint "

查看:102
本文介绍了django update_or_create 获取“重复键值违反唯一约束";的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

也许我误解了 Django 的 update_or_create 模型方法的用途.

Maybe I misunderstand the purpose of Django's update_or_create Model method.

这是我的模型:

from django.db import models
import datetime
from vc.models import Cluster

class Vmt(models.Model):
    added = models.DateField(default=datetime.date.today, blank=True, null=True)
    creation_time = models.TextField(blank=True, null=True)
    current_pm_active = models.TextField(blank=True, null=True)     
    current_pm_total = models.TextField(blank=True, null=True)
    ... more simple fields ...
    cluster = models.ForeignKey(Cluster, null=True)


    class Meta:
        unique_together = (("cluster", "added"),)

这是我的测试:

from django.test import TestCase
from .models import *
from vc.models import Cluster
from django.db import transaction


# Create your tests here.
class VmtModelTests(TestCase):
    def test_insert_into_VmtModel(self):
        count = Vmt.objects.count()
        self.assertEqual(count, 0)

        # create a Cluster
        c = Cluster.objects.create(name='test-cluster')
        Vmt.objects.create(
            cluster=c,
            creation_time='test creaetion time',
            current_pm_active=5,
            current_pm_total=5,
            ... more simple fields ...
        )
        count = Vmt.objects.count()
        self.assertEqual(count, 1)
        self.assertEqual('5', c.vmt_set.all()[0].current_pm_active)

        # let's test that we cannot add that same record again
        try:
            with transaction.atomic():

                Vmt.objects.create(
                    cluster=c,
                    creation_time='test creaetion time',
                    current_pm_active=5,
                    current_pm_total=5,
                    ... more simple fields ...
                )
                self.fail(msg="Should violated integrity constraint!")
        except Exception as ex:
            template = "An exception of type {0} occurred. Arguments:
{1!r}"
            message = template.format(type(ex).__name__, ex.args)
            self.assertEqual("An exception of type IntegrityError occurred.", message[:45])

        Vmt.objects.update_or_create(
            cluster=c,
            creation_time='test creaetion time',
            # notice we are updating current_pm_active to 6
            current_pm_active=6,
            current_pm_total=5,
            ... more simple fields ...
        )
        count = Vmt.objects.count()
        self.assertEqual(count, 1)

在最后一次 update_or_create 调用中,我收到此错误:

On the last update_or_create call I get this error:

IntegrityError: duplicate key value violates unique constraint "vmt_vmt_cluster_id_added_c2052322_uniq"
DETAIL:  Key (cluster_id, added)=(1, 2018-06-18) already exists.

为什么模型没有更新?为什么 Django 尝试创建违反唯一性约束的新记录?

Why didn't wasn't the model updated? Why did Django try to create a new record that violated the unique constraint?

推荐答案

update_or_create(defaults=None, **kwargs) 基本上有两部分:

  1. **kwargs 指定过滤器"标准来确定这样的对象是否已经存在;和
  2. defaults 这是一个字典,其中包含映射到我们创建新行时应该使用的值的字段(以防过滤找不到行),或者应该更新哪些值(以防我们找到这样的行).
  1. the **kwargs which specify the "filter" criteria to determine if such object is already present; and
  2. the defaults which is a dictionary that contains the fields mapped to values that should be used when we create a new row (in case the filtering fails to find a row), or which values should be updated (in case we find such row).

这里的问题是你让你的过滤器过于严格:你添加了几个过滤器,结果数据库找不到这样的行.那么会发生什么?然后,数据库旨在创建具有这些过滤器值的行(并且由于缺少 defaults,因此不会添加额外的值).但是后来发现我们创建了一行,并且 cluster added 的组合已经存在.因此数据库拒绝添加这一行.

The problem here is that you make your filters too restrictive: you add several filters, and as a result the database does not find such row. So what happens? The database then aims to create the row with these filter values (and since defaults is missing, no extra values are added). But then it turns out that we create a row, and that the combination of the cluster and added already exists. Hence the database refuses to add this row.

所以这一行:

Model.objects.update_or_create(field1=val1,
                               field2=val2,
                               defaults={
                                   'field3': val3,
                                   'field4': val4
                               })

在语义上近似等于:

try:
    item = Model.objects.get(field1=val1, field2=val2)
except Model.DoesNotExist:
    Model.objects.create(field1=val1, field2=val2, field3=val3, field4=val4)
else:
    item = Model.objects.filter(
        field1=val1,
        field2=val2,
    ).update(
        field3 = val3
        field4 = val4
    )

(但原始调用通常在单个查询中完成).

(but the original call is typically done in a single query).

你可能应该这样写:

Vmt.objects.update_or_create(
    cluster=c,
    creation_time='test creaetion time',
    defaults = {        
        'current_pm_active': 6,
        'current_pm_total': 5,
    }
)

(或类似的东西)

这篇关于django update_or_create 获取“重复键值违反唯一约束";的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆