我正在尝试使用postgresql数据库为django中的表模型设置约束。
我可以通过postgresql用这句话来做:
ALTER TABLE public.mytable ADD CONSTRAINT "myconstraint" UNIQUE(field1, field2) DEFERRABLE INITIALLY DEFERRED;
但我想通过django模型来做。 阅读django官方文档我没有发现任何相关内容。
我需要这样的东西:
class Meta:
unique_together = (('field1', 'field2',), DEFERRABLE INITIALLY DEFERRED)
是否可以做这样的事情?
答案 0 :(得分:2)
Django不支持。
您可以使用自定义SQL执行此操作。在models.py
中添加以下内容:
from django.db import connection
from django.db.models.signals import post_migrate
def after_migrate(sender, **kwargs):
cursor = connection.cursor()
cursor.execute('ALTER TABLE public.mytable ALTER CONSTRAINT '
'myconstraint DEFERRABLE INITIALLY DEFERRED')
post_migrate.connect(after_migrate)
虽然我过去做过这样的事情,但我发现多年来我更喜欢让我的工作更简单,更独立于任何特定的RDBMS。例如,您确实希望支持SQLite,因为它使开发变得更加容易。设计稍有变化,你可以经常摆脱这些东西。
答案 1 :(得分:1)
我将通过一次迁移来做到这一点。首先以编程方式获取唯一的约束名称,然后删除并重新添加(因为更改它似乎仅适用于FK约束,而不适用于唯一约束)。添加反向迁移也可以消除这种情况。
from django.db import migrations, connection
def _make_deferrable(apps, schema_editor):
"""
Change the unique constraint to be deferrable
"""
# Get the db name of the constraint
MyModel = apps.get_model('myapp', 'MyModel')
CONSTRAINT_NAME = schema_editor._constraint_names(MYModel,
['col1', 'col2'],
unique=True)[0]
TABLE_NAME = MyModel._meta.db_table
# Drop then re-add with deferrable as ALTER doesnt seem to work for unique constraints in psql
with schema_editor.connection.create_cursor() as curs:
curs.execute(
f'ALTER TABLE {TABLE_NAME} DROP CONSTRAINT "{CONSTRAINT_NAME}";'
)
curs.execute(
f'ALTER TABLE {TABLE_NAME} ADD CONSTRAINT'
f' {CONSTRAINT_NAME}'
f' UNIQUE (col1, col2) DEFERRABLE INITIALLY DEFERRED;'
)
def _unmake_deferrable(apps, schema_editor):
"""
Reverse the unique constraint to be not deferrable
"""
# Get the db name of unique constraint
MyModel = apps.get_model('myapp', 'MyModel')
CONSTRAINT_NAME = schema_editor._constraint_names(MyModel,
['col1', 'col2'],
unique=True)[0]
TABLE_NAME = MyModel._meta.db_table
with schema_editor.connection.create_cursor() as curs:
curs.execute(
f'ALTER TABLE {TABLE_NAME} DROP CONSTRAINT "{CONSTRAINT_NAME}";'
)
curs.execute(
f'ALTER TABLE {TABLE_NAME} ADD CONSTRAINT'
f' {CONSTRAINT_NAME}'
f' UNIQUE (col1, col2) NOT DEFERRABLE;'
)
class Migration(migrations.Migration):
dependencies = [
('myapp', '<previous_mig>'),
]
operations = [
migrations.RunPython(code=_make_deferrable, reverse_code=_unmake_deferrable)
]
答案 2 :(得分:1)
最近,Django新增了对此功能的支持(请参见ticket)。从Django 3.1开始,您可以编写:
class UniqueConstraintDeferrable(models.Model):
name = models.CharField(max_length=255)
shelf = models.CharField(max_length=31)
class Meta:
required_db_features = {
'supports_deferrable_unique_constraints',
}
constraints = [
models.UniqueConstraint(
fields=['name'],
name='name_init_deferred_uniq',
deferrable=models.Deferrable.DEFERRED,
),
models.UniqueConstraint(
fields=['shelf'],
name='sheld_init_immediate_uniq',
deferrable=models.Deferrable.IMMEDIATE,
),
]