在 django 中,如果我有多个 UniqueConstraints,则带有 update_conflicts=True 的bulk_create 不起作用

sim*_*mum 5 django django-models django-rest-framework

假设我有这个模型:

class XYZ(Model):
    id = models.BigAutoField(primary_key=True)
    keys_1 = models.IntegerField()
    keys_2 = models.JSONField(null=False, default=dict)
    keys_3 = models.DateField(null=True, default=None)
    values = models.JSONField(null=False, default=dict)

    class Meta:
        db_table = "xyz"

        constraints = [
            models.UniqueConstraint(
                fields=["keys_1", "keys_2"],
                name="unicity_when_keys_3_null",
                condition=Q(keys_3__isnull=True),
            ),
            models.UniqueConstraint(
                fields=["keys_1", "keys_2", "keys_3"],
                name="unicity",
            ),
        ]

Run Code Online (Sandbox Code Playgroud)

然后我这样做:


XYZ.objects.bulk_create(
        data,
        update_conflicts=True,
        unique_fields=["keys_1", "keys_2", "keys_3"],
        update_fields=["values"],
)
Run Code Online (Sandbox Code Playgroud)

作为对象data列表XYZ

  • 如果data[n].keys_3不是None,则按预期工作
  • 如果data[n].keys_3None,它会在冲突时失败,引用unicity_when_keys_3_null约束

难道我做错了什么 ?

附:

  • 这些不能用
XYZ.objects.bulk_create(
        data,
        update_conflicts=True,
        unique_fields=["keys_1", "keys_2"],
        update_fields=["values"],
)

XYZ.objects.bulk_create(
        data,
        update_conflicts=True,
        unique_fields=["keys_1", "keys_2"],
        update_fields=["values", "keys_3"],
)

Run Code Online (Sandbox Code Playgroud)
  • 这不起作用
        constraints = [
            models.UniqueConstraint(
                fields=["keys_1", "keys_2"],
                name="unicity_when_keys_3_null",
                condition=Q(keys_3__isnull=True),
            ),
            models.UniqueConstraint(
                fields=["keys_1", "keys_2", "keys_3"],
                name="unicity",
                condition=Q(keys_3__isnull=False),
            ),
        ]

Run Code Online (Sandbox Code Playgroud)
  • 一个有效的解决方法是:

        for row in data: # here data is a list of dicts
            ProductDataSourceValues.objects.update_or_create(
                key_1=row["key_1"],
                key_2=row["key_2"],
                key_3=row["key_3"],
                defaults={"values": row["values"]},
            )
Run Code Online (Sandbox Code Playgroud)

Iqb*_*ain 0

模型:

class XYZ(Model):
        id = models.BigAutoField(primary_key=True)
        keys_1 = models.IntegerField()
        keys_2 = models.JSONField(null=False, default=dict)
        keys_3 = models.DateField(null=True, default=None)
        values = models.JSONField(null=False, default=dict)
    
        class Meta:
            db_table = "xyz"
    
            constraints = [
                models.UniqueConstraint(
                    fields=["keys_1", "keys_2", "keys_3"],
                    name="unicity",
                ),
                models.UniqueConstraint(
                    fields=["keys_1", "keys_2"],
                    name="unicity_when_keys_3_null",
                    condition=Q(keys_3__isnull=True),
                ),
            ]  
Run Code Online (Sandbox Code Playgroud)

创建新对象并更新冲突:

    XYZ.objects.bulk_create(
        data,
        update_conflicts=True,
        unique_fields=["keys_1", "keys_2", "keys_3"],
        update_fields=["values"],
    )
Run Code Online (Sandbox Code Playgroud)