Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Partial Indexes with Django 1.7

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;
like image 895
user4150760 Avatar asked Oct 16 '14 17:10

user4150760


People also ask

Does MySQL use partial indexes?

MySQL does not support partial indexes.

How do you create a partial index?

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.

Does Django create indexes?

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.

How do I index a column in Django?

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) .


1 Answers

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.

like image 51
Kevin Christopher Henry Avatar answered Sep 22 '22 03:09

Kevin Christopher Henry