Django создать уникальный индекс функции

С помощью postgresql мы можем создать уникальный индекс функции:

create unique index user_date_checkin
on unique_user_date (user_id, (timezone('UTC'::text, create_time)::date));

Но с Django 3.2:

class UserCheckin(GeneralModel):
   id = models.BigAutoField(primary_key=True)
   user_id = models.BigIntegerField()
   create_time = models.DateTimeField()
   
   class Meta:
       indexes = [
           models.Index("user_id", TruncDate("create_time"), name="user_date_checkin"),
        ]

можно получить только такую генерацию sql:

create index user_date_checkin
    on test (user_id, (timezone('UTC'::text, create_time)::date));

И UniqueConstraint

constraints = [
    models.UniqueConstraint(
        fields=["user_id", TruncDate("create_time")],
        name="user_date"),
]

получил ошибку ссылка на несуществующее поле 'TruncDate(F(create_time))

.

Как я могу создать уникальный индекс с помощью функции в Django 3.2?

обновление

В источнике django django/db/backends/base/schema.py я нашел:

    if condition or include or opclasses:
        sql = self.sql_create_unique_index
    else:
        sql = self.sql_create_unique

Но у меня нет такого условия или опклассов в этом случае

обновление

После добавления условия:

    indexes = [
        models.Index("user_id", TruncDate("create_time"),
            condition=Q(user_id__isnull=False), name="user_date_checkin"),
    ]

По-прежнему не добавляйте unique здесь:

-- auto-generated definition
create index user_date_checkin
    on voip_usercheckin (user_id, (timezone('UTC'::text, create_time)::date))
    where (user_id IS NOT NULL);

Django не поддерживает функциональные ограничения пока. Но эта возможность уже находится в разработке и будет частью Django версии 4.0, которая, как ожидается, выйдет в декабре 2021 года. Пока что вы можете выполнить sql через пользовательскую миграцию:

Сначала запустите python manage.py makemigrations yourapp --empty, где yourapp - приложение, в котором находится ваша модель. Затем отредактируйте созданную миграцию и добавьте операцию RunSQL [Django-docs]:

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ...
    ]

    operations = [
        migrations.RunSQL(
            sql="create unique index user_date_checkin on unique_user_date (user_id, (timezone('UTC'::text, create_time)::date));",
            reverse_sql="DROP INDEX IF EXISTS user_date_checkin;"
        ),
    ]

После этого вы можете применить миграцию, запустив python manage.py migrate, что создаст индекс в базе данных.


После выхода Django 4.0 вы, вероятно (может измениться), сможете написать следующее:

constraints = [
    models.UniqueConstraint(
        "user_id",
        TruncDate("create_time"),
        name="user_date"),
]
Вернуться на верх