使用Django 1.7创建部分索引

问题描述 投票:12回答:2

Django 1.7的documentation提到RunSQL类可用于在表上创建部分索引。我有一张桌子,我希望titleblogcategory的组合是独一无二的。但是,如果未提供类别,则标题和博客的组合仍应是唯一的。

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;
django django-models django-orm django-1.7 django-migrations
2个回答
21
投票

Django 2.2及更高版本

从版本2.2开始,Django支持declarative partial unique indexes支持它们的数据库(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)),
        ]

Django 2.1及更早版本

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

python manage.py makemigrations --empty yourappname

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

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

最后,运行migrate


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将按照你想要的方式工作,如果没有设置,那么title / blog必须是唯一的。

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

© www.soinside.com 2019 - 2024. All rights reserved.