Что это такое?

- -

Management Command — это обычный Python-скрипт, который "встраивается" в экосистему Django. Он имеет доступ к моделям, настройкам (settings.py) и базе данных, но запускается из консоли через python manage.py ....

- +

Management Command — это обычный Python-скрипт, который «встраивается» в экосистему Django. Он имеет доступ к моделям, настройкам (settings.py) и базе данных, но запускается из консоли через python manage.py ....

Зачем это нужно?

Представьте ситуации:

-

Делать это через views.py (views) — плохая идея (страница может отвалиться по тайм-ауту). Писать отделный скрипт рядом manage.py — неудобно (нужно вручную настраивать `DJANGO_SETTINGS_MODULE`). Встроенные команды решают эти проблемы элегантно.

- -

Как это работает?

-

Django использует систему "автообнаружения" (auto-discovery). Чтобы ваша команда появилась в списке `manage.py`, нужно соблюсти строгую иерархию папок внутри вашего приложения (например, web):

+

Делать это через views.py (views) — плохая идея (страница может отвалиться по тайм-ауту). Писать отделный скрипт рядом manage.py — неудобно (нужно вручную настраивать `DJANGO_SETTINGS_MODULE`). Встроенные команды решают эти проблемы элегантно.

+

Как это работает?

+

Django использует систему «автообна­ружения» (auto-discovery). Чтобы ваша команда появилась в списке `manage.py`, нужно соблюсти строгую иерархию папок внутри вашего приложения (например, web):

web/
 ├── __init__.py
 ├── models.py
-└── management/                 🠀 1. Создаем папку management
+└── management/                 <-- 1. Создаем папку management
     ├── __init__.py
     └── nginx/
-        ├── commands/           🠀 2. Внутри неё папку commands
+        ├── commands/           <-- 2. Внутри неё папку commands
         ├── __init__.py
-        └── my_cool_script.py   🠀 3. Наш файл с командой
-

Файл my_cool_script.py автоматически превратится в команду: python manage.py my_cool_script. Django будет искать его в папках management/commands/ внутри каждого установленного приложения. Это позволяет легко организовать код и держать все "команды обслуживания" в одном месте.

-

Для справки: Механизм Custom Management Commands появился еще в Django 0.96 (в глубокой древности) и с тех пор является стандартом де-факто для написания скриптов обслуживания.

- + └── my_cool_script.py <-- 3. Наш файл с командой +

Файл my_cool_script.py автома­тически превратится в команду: python manage.py my_cool_script. Django будет искать его в папках management/commands/ внутри каждого устано­вленного приложения. Это позволяет легко организовать код и держать все «команды обслуживания» в одном месте.

+

Для справки: Механизм Custom Management Commands появился еще в Django 0.96 (в глубокой древности) и с тех пор является стандартом де-факто для написания скриптов обслуживания.

Анатомия команды

-

Вот пример простейшей команды. Мы наследуемся от класса BaseCommand и переопределяем метод handle:

+

Вот пример простейшей команды. Мы наследуемся от класса BaseCommand и переопре­деляем метод handle:

 # web/management/commands/hello.py
 from django.core.management.base import BaseCommand
@@ -77,20 +73,16 @@ class Command(BaseCommand):
         # Главная логика
         name = options['name']
         self.stdout.write(f"Привет, {name}!")
- -Запуск: -```bash -python manage.py hello Иван -# Вывод: Привет, Иван! -``` - -## Реальный пример: Массовая типографика - -В нашем проекте возникла задача: у нас есть тысячи цитат, сохраненных со старой разметкой. Мы хотим "прогнать" их все через новый типограф `etpgrf` с новыми настройками (висячая пунктуация слева). - -Вот как мы это реализовали в `reprocess_typography.py`: - -```python +

Запуск:

+
+python manage.py hello Иван
+

Увидим в консоли:

+
+Привет, Иван!
+

Реальный пример: Массовая типографика через etpgrf

+

В моём проекте, DQ – коллекция цитат. Место для вдумчивого чтения, контент был частично обработан с помощью Типографа Муравьёа, частично вручную. И вот я установил и настроил etpgrf (тем более что Типограф Муравьева «почил в бозе», да и до того не обновлялся с 2018 года). Все новые цитаты типогра­фируются через etpgrf, но что делать со старыми? Их сотни, и открывать и «пересо­хранаять» каждую вручную — это адский труд. Вот тут на помощь и приходит Custom Management Command.

+

Вот как я это реализовал: в web/management/commands/reprocess_typography.py:

+
 from django.core.management.base import BaseCommand
 from web.models import TbDictumAndQuotes
 # Импорты библиотеки etpgrf
@@ -157,27 +149,29 @@ class Command(BaseCommand):
                 self.stdout.write(self.style.ERROR(f"Ошибка id={dq.id}: {e}"))
 
 
-        self.stdout.write(self.style.SUCCESS(f"\nГотово!"))
-```
+        self.stdout.write(self.style.SUCCESS(f"\nГотово!"))
+

Возможно вы заметили, что в моем проекте для контента есть два поля: szContent и szContentHTML. В первом хранится «сырой» текст, во втором — результат типогра­фирования. В вашем проекте, скорее всего только одно поле для контента, но по сути это ничего не меняет.

+

Еще интересные фишки, которые исполь­зовались при типогра­фировании:

+
    +
  1. self.stdout.write вместо print – позволяет Django перехва­тывать вывод (например, для тестов) и корректно работать с кодировками.
  2. +
  3. self.style.SUCCESS и self.style.ERROR – раскрашивает текст в консоли (зеленый/красный) и это очень удобно для визуального восприятия логов.
  4. +
  5. Аргумент –dry-run — позволяют безопасно тестировать скрипт на продакшене перед тем, как реально менять данные.
  6. +
  7. Аргументы –limit и –offset — позволяют обрабатывать базу «порциями», что полезно для больших объемов данных (можно запустить несколько процессов параллельно с разными offset).
  8. +
  9. Используется update_fields – позволяет переза­писывать не всю модель целиком (что могло бы затереть изменения, сделанные кем-то другим в ту же секунду), а обновляем только конкретные поля.
  10. +
+

Теперь, чтобы типогра­фировать весь контент, нам достаточно одной строку в терминале, и Django сделает всю грязную работу за нас (не забудьте инициировать виртуальное окружение вашего проекта).

+

Тестовый прогон (безопасно, ничего не сохраняет):

+
+python manage.py reprocess_typography --dry-run
+

Боевой запуск, с изменениями данные в базе:

+
+python manage.py reprocess_typography
+

Если у вас очень много записей, можно запускать по частям:

+
+python manage.py reprocess_typography --limit 1000 --offset 0
+python manage.py reprocess_typography --limit 1000 --offset 1000
+python manage.py reprocess_typography --limit 1000 --offset 2000
-### Фишки, которые мы использовали: - -1. **`self.stdout.write` вместо `print`**: Это важно. Это позволяет Django перехватывать вывод (например, для тестов) и корректно работать с кодировками. -2. **`self.style.SUCCESS / ERROR`**: Раскрашивает текст в консоли (зеленый/красный). Очень удобно для визуального восприятия логов. -3. **Аргументы (`--dry-run`)**: Позволяют безопасно тестировать скрипт на продакшене перед тем, как реально менять данные. -4. **`update_fields`**: При сохранении мы не перезаписываем всю модель целиком (что могло бы затереть изменения, сделанные кем-то другим в ту же секунду), а обновляем только конкретные колонки. - -Теперь, чтобы "починить" всю базу, нам достаточно набрать одну строку в терминале, и Django сделает всю грязную работу за нас. - -## Запуск - -```bash -# Тестовый прогон (безопасно, ничего не сохраняет) -python manage.py reprocess_typography --dry-run - -# Боевой запуск (изменяет данные в базе!) -python manage.py reprocess_typography -```