17

Django 1.7的文档RunSQL提到类可用于在表上创建部分索引。我有一张桌子,我希望title, blog&的组合category是独一无二的。但是,如果没有提供类别,标题和博客的组合仍然应该是唯一的。

class Post(models.Model):
    title = models.CharField(max_length=200)
    blog = models.ForeignKey(Blog)
    category = models.ForeignKey(Category, null=True, blank=True)

我可以使用部分索引来实现这个约束(如下所示的 SQL)。如果我使用 Django 1.7 迁移,我应该在哪里添加此代码?

CREATE UNIQUE INDEX idx1 
  ON Post (title, blog_id, category_id) 
  WHERE category_id IS NOT NULL;

CREATE UNIQUE INDEX idx2 
  ON Post (title, blog_id)
  WHERE category_id IS NULL;
4

2 回答 2

36

Django 2.2 及更高版本

从 2.2 版开始,Django 支持在支持它们的数据库(PostgreSQL 和 SQLite)上声明性的部分唯一索引。因此,您可以执行以下操作:

from django.db.models import Model, Q, UniqueConstraint

class Post(Model):
    ...
    class Meta:
        constraints = [
            UniqueConstraint(
                fields=["title", "blog", "category"],
                name="idx1",
                condition=Q(category__isnull=False)),
            UniqueConstraint(
                fields=["title", "blog"], 
                name="idx2",                    
                condition=Q(category__isnull=True)),
        ]

Django 2.1 及更早版本

在旧版本中,您需要通过迁移来执行此操作。首先创建一个新的空迁移文件:

python manage.py makemigrations --empty yourappname

然后,为每个索引添加适当的RunSQL行:

operations = [
    migrations.RunSQL("CREATE UNIQUE INDEX..."),
    migrations.RunSQL("CREATE UNIQUE INDEX..."),
]

最后,运行migrate

于 2014-10-16T19:14:47.210 回答
0

你可以unique_together像这样提供:

class Post(models.Model):
    title = models.CharField(max_length=200)
    blog = models.ForeignKey(Blog)
    category = models.ForeignKey(Category, null=True, blank=True)

class Meta:
    unique_together = ("title", "blog", "category")

类别的 NULL 将按照您的意愿工作,如果未设置,则标题/博客必须是唯一的。

https://docs.djangoproject.com/en/1.8/ref/models/options/#unique-together

于 2015-11-27T10:52:52.123 回答