Django migrations, как и сам django, это просто волшебный инструмент. Но при этом “волшебство” порой мешает сделать задачу как нужно. Одно из таких “волшебств”, связано с созданием индекса в PostgreSQL без блокировки на запись. Подробнее об этом есть в документацаии.
Стандартный migrations.AddIndex, который создается автоматически при добавлении индекса в модель, выполняет обычный
CREATE INDEX ... и если мы хотим выкатить быстренько в прод и не заблочить запись в таблицу, то нужно отделить
django models state и фактический заапрос в SQL. Для этого есть migrations.SeparateDatabaseAndState.
Весь процесс я сделал в репозиторий ниже по шагам (каждый коммит отдельный шаг)
- В сгенерированном командой makemigrations файле находим 
migrations.AddIndexи переносим в параметрstate_oprationsконструктораmigrations.SeparateDatabaseAndStateссылка на коммит - В параметре 
database_oprationsконструктораmigrations.SeparateDatabaseAndStateдобавляемmigrations.RunSQL()внутри которого добавимsqlиreverse_sql, соответственно запрос выполняемый при “накатке” и “откатке” миграацаии ссылка на коммит - Выключаем выполнение запросаа в транзакции ссылка на коммит
 
После этого можем запускать migrate и получится что django будет понимать что индекс в бд и сама бд получит запрос с CONCURRENTLY. Т.е. мы слегка обманули “волшебство”.