Adding hash index support for exclusion constraint in PostgreSQL

In PostgreSQL you can’t define a unique constraint using a hash index. However, you can enforce uniqueness using an exclusion constraint and a hash index. This is useful for large values that only use equality and that are not referenced by FKs (fields like UIDs, hashes, checksums, URLs, other large texts etc.).

However, the current implementation of ExclusionConstraint in django.contrib.postgres.constraints is limited to gist and spgist. It seems like the implementation haven’t changed much since it was added in 2019.

I made a local change to allow hash to the list of allowed index_types and generated this constraint:

from django.contrib.postgres.constraints import ExclusionConstraint

class ShortUrl(models.Model):
    class Meta:
        constraints = (
            ExclusionConstraint(
                index_type='hash',  # <--- this index type is currently unsupported
                expressions=[
                    (F('url'), '='),
                ],
                name='%(app_label)s_url_unique_hash',
            ),
        )

It produced the expected SQL:

ALTER TABLE "shorturl_shorturl" ADD CONSTRAINT "shorturl_url_unique_hash" EXCLUDE USING hash ("url" WITH =);

After applying the migration the constraint worked as expected.

What will it take to add hash support for ExclusionConstraint in Django?

2 Likes

Opened a ticket #36827 (Adding hash index support for exclusion constraint in PostgreSQL) – Django and a PR ​https://github.com/django/django/pull/20462

1 Like

Hello Haki, really enjoy reading your blog!

Just someone to propose the feature here and and gather minimal support before opening a ticket which you’ve done. Usually adding extra accepted values to existing parameters (e.g. using) are not controversial.

I’ll go ahead and have a look at the ticket and PR.

Thanks Simon, I wasn’t expecting a reply so quickly :slight_smile:

I felt like this was an oversight in the original PR and it’s such a simple change, so I just went ahead with it.

I addressed your comments on the PR, we continue the discussion there.