The documentation for Django 1.7 mentions RunSQL
classes can be used to create partial indexes on your tables. I have a table where I want the combination of title
, blog
& category
to be unique. However if category is not provided, the combination of title & blog should still be unique.
class Post(models.Model):
title = models.CharField(max_length=200)
blog = models.ForeignKey(Blog)
category = models.ForeignKey(Category, null=True, blank=True)
I can achieve this constraint with partial indexes (like the SQL shown below). Where do I add this code if I'm using Django 1.7 migrations?
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;
MySQL does not support partial indexes.
Assume a table like this: CREATE TABLE access_log ( url varchar, client_ip inet, ... ); To create a partial index that suits our example, use a command such as this: CREATE INDEX access_log_client_ip_ix ON access_log (client_ip) WHERE NOT (client_ip > inet '192.168.
If you run this migration as it is, then Django will create the index on the table, and it will be locked until the index is completed. It can take a while to create an index on a very large table, and you want to avoid downtime.
By default, indexes are created with an ascending order for each column. To define an index with a descending order for a column, add a hyphen before the field's name. For example Index(fields=['headline', '-pub_date']) would create SQL with (headline, pub_date DESC) .
Django 2.2 and later
As of version 2.2 Django supports declarative partial unique indexes on databases that support them (PostgreSQL and SQLite). So you could do something like:
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 and earlier
In older versions you need to do this with migrations. First create a new, empty migration file:
python manage.py makemigrations --empty yourappname
Then, for each index add an appropriate RunSQL
line:
operations = [
migrations.RunSQL("CREATE UNIQUE INDEX..."),
migrations.RunSQL("CREATE UNIQUE INDEX..."),
]
Finally, run migrate
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With