unique_together 不使用自引用外键?

jav*_*ved -1 django django-models

class Category(models.Model):
    name = models.CharField(max_length=200)
    parent = models.ForeignKey("self",
                               blank=True,
                               null=True,
                               related_name='children',
                               on_delete=models.CASCADE)

    class Meta:
        unique_together = [
            ('parent', 'name'),
        ]
Run Code Online (Sandbox Code Playgroud)

在这个模型中,我可以使用以下命令创建多个对象

Category.objects.create(name="cat1", parent=None) # 
Category.objects.create(name="cat1", parent=None) 
# unique_together constraint should not 
# allow this second object's reaction, but it is; 
# behavior is the same even when the parent is not None.
Run Code Online (Sandbox Code Playgroud)

我使用的 Django 版本是3.0.8 Postgres 12.3 psycopg2-binary 2.8.5

更新:

Category.objects.create(name="cat1", parent=obj) # 
Category.objects.create(name="cat1", parent=obj) 
Run Code Online (Sandbox Code Playgroud)

即使父对象不是“无”,也会创建第二个对象或记录。

In [2]: Category2.objects.create(name="cat1")                            
Out[2]: <Category2: cat1>

In [3]: Category2.objects.create(name="cat1")                            
Out[3]: <Category2: cat1>

In [4]: par1 = Category2.objects.create(name="cat1")                     

In [6]: par1 = Category2.objects.create(name="cat2", parent=par1)        

In [7]: par2 = Category2.objects.create(name="cat2", parent=par1)  
Run Code Online (Sandbox Code Playgroud)

这个问题不是重复的,它与问题中解释的可空外键无关。

Wil*_*sem 5

数据库在检查唯一性时将忽略 NULL,这意味着两个NULLs 不被视为分支唯一性。

您可以利用约束框架有条件地检查唯一性:

from django.db.models import Q, UniqueConstraint

class Category(models.Model):
    name = models.CharField(max_length=200)
    parent = models.ForeignKey(
        'self',
        blank=True,
        null=True,
        related_name='children',
        on_delete=models.CASCADE
    )

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=['name', 'parent'], name='name_unique'
            ),
            UniqueConstraint(
                fields=['name'], condition=Q(parent=None), name='name_unique2'
            )
        ]
Run Code Online (Sandbox Code Playgroud)

这里如果parent是这样NULL,我们检查 的唯一性name。然而,某些数据库可能不会强制执行此类检查。

显然,在 Microsoft 的 SQL Server 上,情况并非如此,正如@Melvyn所说。在这种情况下,这将是想要的行为。但以我的拙见,这通常是不受欢迎的行为。NULL通常正是用于此目的。