C2H5OH
C2H5OH

Reputation: 5622

Create composite index from a Django model

I have the following model:

from django.db import models

class PopulationData(models.Model):
    slot = models.IntegerField(db_index=True)
    sample = models.IntegerField()
    value = models.FloatField()

    class Meta:
        unique_together = (('slot', 'sample'),)

And I would like to create also a compound index on the column pair that have the UNIQUE constraint, like so:

CREATE INDEX my_compound_index ON myapp_populationdata (slot, sample);

Right now I have a separate code connected to the post_syncdb signal that issues the previous SQL statement. Is there any way to indicate it from the model specification? (Note: I'm using the 1.3 branch).

Upvotes: 29

Views: 25356

Answers (5)

Eugene Prikazchikov
Eugene Prikazchikov

Reputation: 1904

Starting from django-1.5 you can make compound index using index_together meta option: https://docs.djangoproject.com/en/dev/ref/models/options/#index-together

Note (2023/01/30) index_together is deprecated since django-4.2. Instead, use much more powerful indexes meta option. With it you can create not only compound indexes, but also other types of indexes, e.g. function-based indexes, partial (conditional) indexes, covering indexes: https://docs.djangoproject.com/en/dev/ref/models/options/#django.db.models.Options.indexes

So, in your example index declaration would like this

from django.db import models

class PopulationData(models.Model):
    slot = models.IntegerField()
    sample = models.IntegerField()
    value = models.FloatField()

    class Meta:
        indexes = [
            models.Index("slot", "sample", name="population_slot_sample_idx")
        ]

Upvotes: 39

Boketto
Boketto

Reputation: 927

Note: index_together may be deprecated in the future: https://docs.djangoproject.com/en/dev/ref/models/options/#index-together

Use indexes in the Meta class instead:

from django.db import models

class Customer(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    class Meta:
        indexes = [
            models.Index(fields=['last_name', 'first_name']),
            models.Index(fields=['first_name'], name='first_name_idx'),
        ]

Upvotes: 2

Lord Elrond
Lord Elrond

Reputation: 16072

Since a unique constraint also creates an index, it would be counterproductive to create both.

for example, from the postgres docs:

There's no need to manually create indexes on unique columns; doing so would just duplicate the automatically-created index.

Credit to Mark Byers for the doc link

If for some reason you still want to create a multi-column index, you can do so via index_together:

class PopulationData(models.Model):
    ...

    class Meta:
        index_together = [['slot', 'sample']]

Upvotes: 5

Artem Likhvar
Artem Likhvar

Reputation: 103

Starting from Django-1.11 use Meta.indexes option https://docs.djangoproject.com/en/1.11/ref/models/indexes/:

from django.db import models

class PopulationData(models.Model):
    slot = models.IntegerField(db_index=True)
    sample = models.IntegerField()
    value = models.FloatField()

    class Meta:
        unique_together = (('slot', 'sample'),)
        indexes = [
            models.Index(fields=['slot', 'sample']),
        ]

Upvotes: 8

gonz
gonz

Reputation: 5276

I think that's not currently implemented in the django ORM.

If you use a migration tool (like south) that might be a good place to add that sql statement or if you preffer to avoid raw sql you could use sqlalchemy (core) but this case sounds simple enough to just go with sql.

Upvotes: 2

Related Questions