Unique_together在字段为null时不起作用。如何约束它?

huangapple go评论55阅读模式
英文:

Unique_together doesn't work if a field is null. How to constrain it?

问题

我有一个像这样的模型:

class ProductCode(models.Model):
    class Meta:
        unique_together = [('code', 'customer'), ]
    customer = models.ForeignKey('customers.Customer', models.CASCADE, null=True, blank=True)
    code = models.CharField(max_length=20)
    product = models.ForeignKey(Product, models.CASCADE, )
    ...

问题是,如果customerNone(数据库中的空值),则不会强制执行约束。它允许我多次存储具有类似(code='foo', customer=None)的行/对象。我在这个SO帖子中找到了一个建议,该帖子表明对于Postgres用户来说,这个问题是无法修复的。

是否有任何方法可以使用(相对较新的)Meta constraints 来强制执行此约束?我发现文档有点难以理解。

还是我必须实现一个占位符客户来关联“默认”产品代码?

或者,另一种方法是在code之前添加customer的文本表示,然后将其设置为unique=True,在必要时使用__startswith__contains查询。

英文:

I have a model like this

class ProductCode( models.Model):
    class Meta:
        unique_together=[('code','customer'), ] 
    customer = models.ForeignKey( 'customers.Customer', models.CASCADE, null=True, blank=True, )
    code = models.CharField( max_length = 20)
    product = models.ForeignKey( Product, models.CASCADE, )
    ...

The trouble is that if customer is None (DB null) then the constraint is not enforced. It lets me store rows/objects with, say, (code='foo', customer=None) multiple times. I have found this SO post which suggests that the problem is un-fixable for Postgres users.

Is there any way to enforce this constraint with the (relatively) new Meta constraints? I am finding the documentation a bit hard to fathom.

Or do I have to implement a placeholder customer to attach "default" product codes to?

Or, another way would be to prepend a textual representation of customer to code and then just make it unique=True and use __startswith= and __contains lookups where necessary.

答案1

得分: 0

这是预期行为:在数据库中,NULL 在某种意义上非常特殊,因为 NULL 不等于非 NULL

您可以添加第二个唯一性约束,用于在其他字段为 NULL 时使用,如下所示:

from django.db.models import Q

class ProductCode(models.Model):
    customer = models.ForeignKey(
        'customers.Customer',
        models.CASCADE,
        null=True,
        blank=True,
    )
    code = models.CharField(max_length=20)
    product = models.ForeignKey(
        Product,
        models.CASCADE,
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=('code', 'customer'), name='code_customer_unique1'
            ),
            models.UniqueConstraint(
                fields=('code',),
                condition=Q(customer=None),
                name='code_customer_unique2',
            ),
        ]

注意: 正如关于 unique_together文档所述,unique_together 约束可能会被弃用。文档建议使用 Django 的 UniqueConstraint 从 Django 的约束框架

英文:

This is expected behavior: in a database NULL is quite special in the sense that NULL is not equal not NULL.

You can add a second uniqness constraint that is used when the other field is NULL, so:

<pre><code>from django.db.models import Q

class ProductCode(models.Model):
customer = models.ForeignKey(
'customers.Customer',
models.CASCADE,
null=True,
blank=True,
)
code = models.CharField(max_length=20)
product = models.ForeignKey(
Product,
models.CASCADE,
)

class Meta:
    constraints = [
        models.UniqueConstraint(
            fields=(&#39;code&#39;, &#39;customer&#39;), name=&#39;code_customer_unique&lt;sub&gt;1&lt;/sub&gt;&#39;
        ),
        models.UniqueConstraint(
            fields=(&#39;code&#39;,),
            &lt;b&gt;condition=Q(customer=None)&lt;/b&gt;,
            name=&#39;code_customer_unique&lt;sub&gt;2&lt;/sub&gt;&#39;,
        ),
    ]&lt;/code&gt;&lt;/pre&gt;

> Note: As the documentation on unique_together&nbsp;<sup>[Django-doc]</sup> says, the unique_together constraint will likely become deprecated. The documentation advises to use the UniqueConstraint&nbsp;<sup>[Django-doc]</sup> from Django's constraint
> framework
.

huangapple
  • 本文由 发表于 2023年5月24日 23:39:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76325262.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定