Django's AddConstraint cannot reuse a pre-built index. To avoid the lock, build the index concurrently first and attach it via two RunSQL operations, wrapped in SeparateDatabaseAndState so Django's model state still records the constraint (otherwise the next `makemigrations` regenerates this AddConstraint and re-introduces the lock):

  SeparateDatabaseAndState(
      state_operations=[
          migrations.AddConstraint(
              model_name='<table>',
              constraint=models.UniqueConstraint(fields=[<cols>], name='<name>'),
          ),
      ],
      database_operations=[
          migrations.RunSQL('CREATE UNIQUE INDEX CONCURRENTLY <name> ON <table> (<cols>);'),
          migrations.RunSQL('ALTER TABLE <table> ADD CONSTRAINT <name> UNIQUE USING INDEX <name>;'),
      ],
  )

Two RunSQL operations are required because `CREATE INDEX CONCURRENTLY` must run outside a transaction; bundling both statements in one RunSQL would still be a single transaction. Set `atomic = False` on the migration so RunSQL doesn't open one.
