#36. Management commands
Management Commands
Менеджмент команды и настройки.
Management commands в рамках Django - это возможность запустить скрипт из консоли для выполнения абсолютно различных действий.
Наиболее частые сферы применения — это действия, выполняемые разово или периодически. Например, отправка пользователям разовых сообщений, получение выборки данных из БД, проверка наличия необходимых файлов и папок перед накатыванием обновлений, быстрое создание объектов модели при разработке и т.д.
Существует три способа запуска менеджмент команды
django-admin <command> [options]
python manage.py <command> [options]
python -m django <command> [options]
В случае запуска через django-admin
вы можете указать какой файл настроек использовать при помощи опции --settings
.
Если вы запускаете команду через manage.py
(самый распространенный способ) файл настроек будет выбран в соответствии с самим файлом manage.py
, так как информация о файле настроек для Django проекта находится именно в файле manage.py
, в DJANGO_SETTINGS_MODULE
Мы уже использовали некоторые команды, но давайте посмотрим подробнее.
Доступные команды
help
Список доступных команд
>>> python manage.py help
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
[auth]
changepassword
createsuperuser
[contenttypes]
remove_stale_contenttypes
[django]
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject
test
testserver
[sessions]
clearsessions
[staticfiles]
collectstatic
findstatic
runserver
Интернационализация и локализация
В Django уже есть встроеннае поддержка переводов.
Django полностью поддерживает перевод текста, форматирование дат, времени и чисел, а также часовых поясов.
Подробнее тут
Слова «интернационализация» и «локализация» часто вызывают путаницу.
Интернационализация - это процесс разработки программных приложений, которые потенциально могут адаптироваться к различным языкам и регионам без инженерных изменений (т.е. подготовка программы к локализации.). Обычно это делают разработчики.
Локализация - это процесс адаптации интернационализированного программного обеспечения для определенного региона или языка путем добавления локальных компонентов и переведенного текста. (проще говоря, написание переводов и локальных форматов). Обычно это делают переводчики.
Для добавления строки в список для перевода ее необходимо передавать в gettext
from django.utils.translation import gettext as _
_('Translate it')
В теплейтах используется тег translate
(до Django 3.0 включительно был тег trans
). Для его подключение необходимо подкгрузить модуль i18n
вверху шаблона :
{% load i18n %}
{% translate "This is the title." %}
{% translate myvar %}
Либо blocktranslate
для многострочных строк:
{% load i18n %}
{% blocktranslate %}Back to '{{ race }}' homepage{% endblocktranslate %}
В settings.py
есть переменные, отвечаюшие за перевод:
LANGUAGE_CODE = 'en-us' # язык по умолчанию, можно поставить ru, и даже админка станет на русском
USE_I18N = True # i18n - сокращение от 'internationalization'
USE_L10N = True # L10n - от 'localization'
makemessages
python manage.py makemessages
Команда для работы с переводами (локализацией) сайтов.
Переводы попадут в папку locale
приложения, если ее нет - ее необходимо создать!
Команда проходит через весь код и ищет места, которое заготовлены для перевода (для python кода, это везде где вы используете метод gettext
, для шаблонов везде где используется темплейт тег translate
, )
Создаёт\Обновляет файлы в которых хранятся\будут храниться переводы текста на друге языки. Принимает параметры --all
, --extension
, --locale
, --exclude
, --domain
, --ignore
итд.
Подробности использования параметров тут
Обсудим основные.
--locale LOCALE, -l LOCALE
нужно, чтобы указать на какой язык планируется перевод (на самом деле повлияет только на то, как будет называться файл с переводами, и как этот перевод будет называться в системе), например для французского можно
назвать файл fr
, для итальянского it
итд.
django-admin makemessages --locale=pt_BR
django-admin makemessages --locale=pt_BR --locale=fr
django-admin makemessages -l pt_BR
django-admin makemessages -l pt_BR -l fr
--ignore PATTERN
- Игнорировать (не искать) переводы в определённых местах, например `–ignore *.py’ - игнорировать все пайтон файлы.
Создаст файлы с расширением .po
и списком всех мест где нужно будет указать перевод
>>> python manage.py makemessages -l=ru
>
processing locale ru
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-18 22:33+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: myapp/models.py:22
msgid "Not selected"
msgstr ""
#: myapp/models.py:23
msgid "Comedy"
msgstr ""
#: myapp/models.py:24
msgid "Action"
msgstr ""
#: myapp/models.py:25
msgid "Beauty"
msgstr ""
#: myapp/models.py:26
msgid "Other"
msgstr ""
#: myapp/templates/base.html:6
msgid "Title"
msgstr ""
Комментом указано, откуда конкретно взят текст для перевода, ниже сам текст который нужно перевести, и место где мы можем указать перевод.
compilemessages
Компилирует файлы для переводов.
Делает из .po
(Portable Object) файлов .mo
(Machine Object) файлы. Django принимает именно .mo
как файлы откуда брать перевод.
Поддерживает указание локали и игнор, подробнее в документации)
>>> python manage.py compilemessages
processing file django.po in mysite/myapp/locale/ru/LC_MESSAGES
createcachedtable
Создаёт таблицу для кеша в базе данных, подробно рассматривали на занятии по сессиям и кешам.
Остальные команды
check
python manage.py check [app_label [app_label ...]]
Например:
>>> python manage.py check auth admin myapp
System check identified no issues (0 silenced).
Команда для запуска проверки кода на качество (например, что неправильно указаны аргументы модели, или некорректно указано свойство для класса админки, итд. список огромный)
Посмотреть базовый список проверок можно тут.
shell
Уже известная вам команда shell
открывает интерактивную python
консоль, с уже импортированными библиотеками вашего проекта, например Django.
dbshell
По аналогии со знакомой нам командой shell
открывает консоль со всеми необходимыми импортированными данными, но для базы данных.
Например для postgresql, откроется psql
итд.
diffsettings
Команда, которая покажет чем, отличается ваш файл settings.py
от оригинала.
Фискстуры
dumpdata
Команда для работы с фикстурами.
Фикстуры - это заранее подготовленные данные. В основном, это файлы отображения базы данных в формат JSON.
Команда dumpdata
вытащит все данные из базы данных, и преобразует всё в формат JSON.
Может принимать имя только нескольких приложений, или даже только некоторых моделей, или наоборот исключить какие-то приложения или модели
loaddata
Команда, обратная команде dumpdata
. Для загрузки JSON файла в базу данных.
Подробно будем рассматривать эти командны на практике занятия по тестированию джанго.
flush
Команда необходимая для очистки базы данных, но не отмены миграций (Сохраняем структуру, теряем все данные)
sqlflush
Отпечатает какой SQL код будет выполнен при применении команды flush
inspectdb
Команда необходимая для проверки соответствия ваших моделей и вашей базы данных. Незаменимо при переносе проекта из вне на Django.
Миграции
makemigrations
Уже известная вам команда, которая создаёт файлы миграций, и может принимать имя приложения, чтобы создать только для конкретного приложения.
Может принимать важный параметр --empty
, при этом флаге создастся пустая миграция, никак не привязанная к моделям.
Выглядеть будет примерно вот так:
>>> python manage.py makemigrations myapp --empty
Migrations for 'myapp':
myapp/migrations/0004_auto_20211018_2255.py
# Generated by Django 3.2.7 on 2021-10-18 22:55
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('myapp', '0003_note'),
]
operations = [
]
Тут указано приложение для которого миграция будет применена, и прошлая миграция с которой текущая миграция будет
связана.
Зачем это вообще надо?
Мы можем в операции добавить любые интересующие нас действия, например выполнения кода на python
Для этого нужно добавить класс RunPython
из пакета migrations
, который будет принимать два метода, первый будет выполнен в случае выполнения миграции, второй в случае отката миграции.
# Generated by Django 3.0.7 on 2020-10-29 11:59
from django.db import migrations
def some_forward_action(apps, schema_editor):
Team = apps.get_model('storages', 'Team') # Приложение и модель
names = ('B2B', 'CX', 'SFA')
teams = []
for name in names:
teams.append(Team(name=name))
Team.objects.bulk_create(teams)
def some_backward_action(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('storages', '0003_auto_20201029_1352'),
]
operations = [
migrations.RunPython(some_forward_action, some_backward_action)
]
Такие миграции называются Data Migrations
Чаще всего для того чтобы занести какие-либо данные в базу данных на этапе миграции, например, создать заведомо известные объекты, как в моём примере, или для установки вычисляемого значения по умолчанию.
Для обратной миграции чаще всего действия не требуются (хоть и далеко не всегда), поэтому чаще всего обратная миграция не указывается вовсе или записывается в виде лямбда выражения lambda x, y: None
Также можно выполнять чистый SQL, используя класс RunSQL
:
operations = [
migrations.RunSQL("INSERT INTO musician (name) VALUES ('Reinhardt');")
]
migrate
Уже известная вам команда для применения миграции
manage.py migrate [app_label] [migration_name]
Может быть указано приложение, к которому применяется, и имя миграции (на самом деле достаточно первых четырех цифр), указывание имени нужно для отката миграций, допустим у вас уже применена миграция номер 8, а вы поняли, что проблема была в миграции номер 6, это значит что можно откатить базу о миграции номер 5, естественно с потерей данных, и провести новые миграции, для этого нужно сделать:
manage.py migrate my_app 0002
Важным флагом является --fake
, при применении этого флага, изменения в базу внесены не будут, но Django будет видеть, что миграция была применена, нужно, чтобы использовать базы с уже заполненными данными, созданными вне django проекта.
Вместо цифр можно указать значение zero, что позволяет откатить всю миграции для этого приложения.
sqlmigrate
Отпечатает какой SQL код будет выполнен при применении команды migrate
showmigrations
Также уже известная вам команда, которая отобразит список миграций, и их состояние (Применена или нет)
runserver
Команда для запуска тестового сервера, можно указывать порт и многие другие настройки Не применяется на продакшене, только для разработки. Как это делается на продакшене рассмотрим в следующих лекциях.
sendtestemail
Отправка тестового имейла (работает только если отправка писем была настроена) принимает два параметра, от кого и кому.
Например:
python manage.py sendtestemail myownemail@gmail.com myanotheremail@gmail.com
sqlsequencereset
Команда для сброса последовательностей базы данных, может принимать название приложения.
Если вы удалите все объекты из базы, и начнёте создавать новые, id будут продолжаться в не зависимости от того сколько
объектов было раньше, потому что id
вычисляется из специальных объектов базы которые называются sequence
.
Если из сбросить, то id будет назначаться снова с 1
.
Не применять на базах с данными!!
squashmigrations
Команда, которая применяется для того, чтобы сжать
несколько миграций в одну.
Например в приложении myapp
миграции от 4-ой до 7-ой это добавления новых полей в одну и туже модель, чтобы сжать эти
миграции в одну нужно выполнить
python manage.py squashmigrations myapp 0004 0007
startapp
Команда для создания нового приложения.
startproject
Команда для создания нового проекта.
test
Команда для запуска тестов. Рассмотрим её на следующих занятиях.
Команды базовых приложений
django.contrib.auth
changepassword
Команда для смены пароля конкретному пользователю
manage.py changepassword ringo
createsuperuser
Команда для создания пользователя со всеми правами
django.contrib.sessions
clearsession
Команда для очистки базы данных от информации о сессиях. При базовых настройках вся информация о сессиях автоматически пишется в базу данных.
django.contrib.staticfiles
collectstatic
Команды для статики, вообще работу статики и медиа, рассмотрим на следующих занятиях
Написание своих скриптов
Документация
По факту все выше описанные команды написаны на python, а это значит, что мы можем написать свои команды.
Все команды должны храниться внутри папки вашего проекта appname/management/commands/, если у вас отсутствуют эти директории, их необходимо создать.
myapp/
__init__.py
models.py
management/
commands/
welcome.py
tests.py
views.py
Название будет присвоено такое же, как и у файла в котором она записана. То-есть, создав модуль под названием welcome.py
, чтобы в дальнейшем выполнить эту команду необходимо ввести:
python3 manage.py welcome
welcome.py
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "say hello"
def handle(self, *args, **options):
self.stdout.write(self.style.SUCCESS('Welcome'))
Команды должны наследовать от класса BaseCommand
, и класс должен обязательно называться Command, так как Django будет искать по этому имени. Если мы назовем класс с другим именем, то при выполнении команды мы получим ошибку.
В атрибут help мы помещаем текст, который будет описывать, что команда делает, и именно этот текст будет показан при выполнении команды python3 manage.py help <command
>. Код команды должен быть определен внутри метода handle.
Использование аргументов
Команды принимают два типа аргументов: именованные и позиционные.
Именованные аргументы это аргументы с префиксом ‘-‘ или ‘–‘ и не имеет значения, в каком порядке они будут передаваться команде.
Позиционные аргументы не имеют префикса и должны передаваться в том же порядке, в котором они заданы.
Аргументы в командах обрабатываются стандартной библиотекой Python argparse, поэтому обязаны удовлетворять ее спецификациям. Метод, называемый add_arguments, должен быть добавлен в команды, чтобы разрешить использование аргументов в пользовательской команде.
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def add_arguments(self, parser):
# позиционный аргумент
parser.add_argument('name', type=str)
# именованный аргумент
parser.add_argument('-l', '--lastname', type=str, help='Last Name')
def handle(self, *args, **options):
name = options['name']
lastname = options['lastname']
self.stdout.write(self.style.SUCCESS(f'Welcome {name} {lastname}'))
В приведенном выше примере аргумент может быть указан как -l
или --lastname
.
>>> python3 manage.py welcome Name --lastname Lastname
Welcome Name Lastname
Аргументы со значениями по умолчанию
Для упрощения работы хочется, чтобы простой передачи аргумента было достаточно, для понимания, что делать в дальнейшем.
Для того чтобы создать аргумент со значением по умолчанию, при вызове метода add_argument, нам нужно добавить параметр action
.
Значение параметра action будет зависеть от типа и значения по умолчанию. Если вы хотите, чтобы аргумент был булевым, то-есть при его присутствии, он должен быть True
или False
, он должен иметь значение store_true
или store_false
соответственно:
parser.add_argument('--noreload', action='store_true')
Аргументы также могут быть постоянными или делать действительно интересные вещи. Если вы обратитесь к официальной документации argparse
, вы можете знать все, что можно сделать с помощью параметра action. Это пример того, как мы можем хранить константу по умолчанию:
parser.add_argument('--foo', action='store_const', const=42)
Задания
- Снять фикстуру с вашей базы, изучить полученный файл.
- Для вашего модуля создать дата миграцию, которая будет создавать два новых товаров.
- Написать менеджмент команду, чтобы отклонить все заявки на возврат.