Что это, и зачем?
Среди функционала, предоставляемого Django, есть возможность запуска скриптов, взаимодействующих с контекстом django-приложения, через manage-команду runscript.
Такие скрипты обычно создаются для действий по типу выгрузки данных из БД, заполнения БД тестовым пуллом объектов и других задач, которые выполняются по требованию, причем не настолько часто, чтобы создавать элемент в веб-интерфейсе для их вызова.
Также стоит упомянуть возможность запуска таких скриптов в CI/CD pipeline, что удобно для автоматизации.
Как запустить?
Структура Django-проекта довольно строго определена, и при создании скрипта также небоходимо учитывать это: скрипты должны располагаться в директориях ./scripts ваших Django-приложений (app).
Например, допустим, у вас есть приложения first_app и second_app:
django_project_dir/
├-first_app/
│ └-scripts/
│ ├-first_script.py
├-second_app/
│ └-scripts/
│ ├-second_script.py
├-manage.py
├-other_folder/
│ └-some_file.py
Тогда все скрипты, находящиеся в директориях first_app/scripts и second_app/scripts будут зарегистрированы и доступны к исполнению через интерфейс manage.py runscript:
python ../manage.py runscript first_script second_script
У команды runscript есть несколько опций, например:
-
--continue-on-error позволяет продолжить выполнение цепочки скриптов внутри одного вызова runscript при ошибке внутри нее
-
--no-traceback и --traceback отвечают за отображение цепочек вызовов при ошибках
-
--script-args используется для задания аргументов, которые будут переданы в скрипт. Аргументы должны быть разделены пробелом
Более подробно с опциями можно ознакомиться, выполнив команду
python ../manage.py help runscript
Пишем свой скрипт
Наконец, перейдем к созданию своего скрипта. На самом деле в этом нет ничего сложного: скрипт должен представлять из себя файл с функцией run, которая и будет вызвана. Например вот простейший скрипт для удаления всех объектов из таблицы БД:
# scripts/delete_all_questions.py
from polls.models import Question
def run():
# Fetch all questions
questions = Question.objects.all()
# Delete questions
questions.delete()
Также мы можем передать аргументы в скрипт, и использовать их там:
# scripts/delete_all_questions.py
from datetime import timedelta
from django.utils import timezone
from polls.models import Question
def run(*args):
# Получаем все объекты
questions = Question.objects.all()
# В зависимости от аргумента выполняем либо не выполняем фильтрацию
if 'staleonly' in args:
questions = questions.filter(pub_date__lt=timezone.now() - timedelta(days=100))
# Удаляем объекты
questions.delete()
Для запуска скрипта с аргументом (в примере выше это аргумент stateonly) вызов будет выглядеть так:
python manage.py runscript delete_all_questions --script-args staleonly
Стоит упомянуть, что для обозначения исключений при исполнении скриптов принято использовать встроенный класс CommandError.