Ограничение Django DB - разрешить только один объект с полем статуса не "черновик"
У меня есть модель Application
с полями bank
, mortgage
и status
. Для одинаковых bank
и mortgage
я хочу разрешить только одно application
с status
отличным от DRAFT.
class Application(..):
bank = ..
mortgage = ..
status = .. # draft, active, in_progress etc.
Таким образом, может быть несколько таких применений:
# ok
Application(bank=1, mortgage=2, status='draft')
# ok, tuple mortgage and bank already exists but but status is draft
Application(bank=1, mortgage=2, status='draft')
# ok, tuple mortgage and bank already exists but status is active
Application(bank=1, mortgage=2, status='active')
# ERROR - tuple mortgage and bank already exists and there is already one object with same tuple bank, and non-draft status
Application(bank=1, mortgage=2, status='in_progress')
# ok - bank is different
Application(bank=3, mortgage=2, status='active')
Другими словами, я не могу создать приложение с тем же банком, той же ипотекой и статусом не draft
, если уже есть приложение с тем же банком, ипотекой и статусом не draft
.
Возможно ли сделать такое ограничение? Будет ли CheckConstraint
работать?
К сожалению, проверочное ограничение не работает. Контрольное ограничение не может ссылаться за пределы текущего ряда. (См. Документация Примечания.) Похоже, что частичный уникальный индекс тоже не работает. Вы, очевидно, ограничены триггером. Что-то вроде: (см. demo)
create or replace function just_1_non_draft()
returns trigger
language plpgsql
as $$
begin
if exists (select null
from application
where (bank, mortage) = (new.bank,new.mortage)
and status != 'draft'
)
then
raise exception 'Bank %, Mortage % already has non-draft status',new.bank, new.mortage;
end if;
return new;
end;
$$;
create trigger just_1_non_draft_biur
before insert or update of status
on application
for each row
when (new.status != 'draft')
execute function just_1_non_draft();
Вы можете использовать UniqueConstraint с условием
class Application(models.Model):
...
class Meta:
constraints = [
models.UniqueConstraint(
fields=['bank', 'mortgage'],
condition=~models.Q(status='draft'),
name='unique_non_draft'
)
]
Вышеуказанное создает уникальное ограничение на комбинации bank
и mortgage
, но только если статус не "черновик"