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"),
]