How can I set a table constraint “deferrable initially deferred” in django model?

前端 未结 3 1275
南旧
南旧 2021-01-05 20:10

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 pub         


        
3条回答
  •  一个人的身影
    2021-01-05 21:03

    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', ''),
        ]
    
        operations = [
            migrations.RunPython(code=_make_deferrable,  reverse_code=_unmake_deferrable)
        ]
    

提交回复
热议问题