使用Django 1.7创建部分索引

use*_*760 13 django django-models django-orm django-1.7 django-migrations

Django 1.7提及类的文档RunSQL可用于在表上创建部分索引.我有一个表,我想的组合title,blogcategory是唯一的.但是,如果未提供类别,则标题和博客的组合仍应是唯一的.

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

我可以使用部分索引实现此约束(如下面显示的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;
Run Code Online (Sandbox Code Playgroud)

Kev*_*nry 24

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"], condition=Q(category__isnull=False)),
            UniqueConstraint(fields=["title", "blog"], condition=Q(category__isnull=True)),
        ]
Run Code Online (Sandbox Code Playgroud)

Django 2.1及更早版本

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

python manage.py makemigrations --empty yourappname
Run Code Online (Sandbox Code Playgroud)

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

operations = [
    migrations.RunSQL("CREATE UNIQUE INDEX..."),
    migrations.RunSQL("CREATE UNIQUE INDEX..."),
]
Run Code Online (Sandbox Code Playgroud)

最后,跑migrate.

  • @user4150760:“sql”参数是创建索引的字符串,正如您上面给出的那样。如果您希望能够回滚迁移,请同时提供“reverse_sql”参数。在这种情况下,这将是等效的“DROP INDEX ...”命令。`state_operations` 参数在这里不适用。 (2认同)