Из реальных проектов:
1. init — инициализирует проект после развёртывания. Туда входит наполнение БД фикстурами, парсер .csv файлов (потому что проще положить актуальный csv, чем пересоздавать фикстуры), который создаёт древовидную структуру объектов модели, добавляет разные фильтры и ещё много чего.
2. warmup_cache — прогревает кэш. Запускается каждую минуту кроном, смотрит на нужные ключи, если их TTL подходит к концу — актуализирует данные и кладёт в кэш. Польза, очевидно, в том, что кэш прогревается не от действий пользователей и юзерам, попавшим на мисс кэша не приходится ждать долго.
3. order_windows — стартует некие "окна", которые ещё не стартанули, но уже надо. То есть, start_time у них попадает в минуту между текущим запуском команды и предыдущим. Таким же образом закрывает "окна". Запускается каждую минуту. И нет, статус нельзя определить по текущему времени, потому что там происходит много подготовительных работ: создание объектов, рассылки емейлов и т.п.
4. orders_update_status — закрывает заказ, выкидывая тех пользователей, которые присоединились к заказу, но не подтвердили его. Запускается каждую минуту.
В общем, всё то, что нельзя выполнить, опираясь на действия пользователей, а только опираясь на время.
Миграции — это то, что выполняется однажды. Мой пример — init можно было бы сделать миграцией, но по каким-то соображениям, которые я не помню, я так не сделал. Скорее всего оттого, чтобы можно было во время разработки выполнять это несколько раз и не бояться удалять/править данные из "инита". Кстати, логичным было бы впихнуть в 0001_initial миграцию выполнение этой management команды.
Миграция — это не только перестроение структуры БД. Данные там тоже могут быть. Например, раньше были группы юзеров A, B и C, а сейчас надо добавить D. Вполне себе миграция. Особенно, если это запрещено делать через админку.