I am trying to set a constraint to a table model in django with a postgresql database.
I can do it via postgresql with this sentence:
ALTER TABLE public.mytable ADD CONSTRAINT "myconstraint" UNIQUE(field1, field2) DEFERRABLE INITIALLY DEFERRED;
But I want to do it via django model. Reading the django official documentation I have not found anything related.
I need something like this:
class Meta:
unique_together = (('field1', 'field2',), DEFERRABLE INITIALLY DEFERRED)
Is it possible to do something like this?
I would do this via a single migration. First programatically get the unique constraint name, then drop and re-add (since altering it seems to only work for FK constraints, not unique constraints). Add reverse migration that undoes this too.
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)
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With