Everything you wanted to know
about the Django framework

Создание пользовательских команд управления в Django

Django распространяется с различными утилитами (командами), выполняемыми в командной строке, которые вызываются с помощью скрипта django-admin.py или manage.py (Custom Django Management Commands). Хорошая вещь в том, что вы также можете добавить свои собственные команды. Они могут хорошо помочь, когда необходимо взаимодействовать с приложением из командной строки терминала, а также их можно использовать в cron — утилите, использующейся для периодического выполнения заданий в определённое время.

Вступление

Перед тем, как начнем писать свои команды, ознакомимся с интерфейсом команднйо строки Django. Как минимум, при начале разработки в Django, вы должны были ознакомиться с такими командами, как startproject, runserver и collectstatic. Полный перечень встроенных команд можно узнать из справки:

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

Свои команды создаются в приложениях: создается каталог management, с вложенным каталогом commands. Пример:

mysite/                                   <-- каталог проекта
 |-- core/                                <-- каталог приложения
 |    |-- management/
 |    |    +-- commands/
 |    |         +-- my_custom_command.py  <-- модуль с кодом команды
 |    |-- migrations/
 |    |    +-- __init__.py
 |    |-- __init__.py
 |    |-- admin.py
 |    |-- apps.py
 |    |-- models.py
 |    |-- tests.py
 |    +-- views.py
 |-- mysite/
 |    |-- __init__.py
 |    |-- settings.py
 |    |-- urls.py
 |    |-- wsgi.py
 +-- manage.py

В качестве названия команды, вызываемой в команднйо строке используется имя файла. В нашем примере файл my_custom_command.py, так что команда будет вызываться следующим образом:

python manage.py my_custom_command

Основной пример

Создадим базовый пример своей команды:

management/commands/what_time_is_it.py

from django.core.management.base import BaseCommand
from django.utils import timezone

class Command(BaseCommand):
    help = 'Displays current time'

    def handle(self, *args, **kwargs):
        time = timezone.now().strftime('%X')
        self.stdout.write("It's now %s" % time)

В основном команда управления Django состоит из класса с именем Command, который наследуется от BaseCommand. Код команды должен быть определен внутри метода handle().

Посмотрите, мы назвали наш модуль what_time_is_it.py. Эта команда может быть выполнена как:

python manage.py what_time_is_it

Вывод исполнения команды:

It's now 18:35:31

Возникает вопрос, чем это отличается от обычного скрипта Python или в чем его польза. Наилучшим преимуществом является то, что все возможности Django доступны и готовы к использованию, что можно импортировать модели, выполнять запросы в базу данных с помощью ORM Django и взаимодействовать со всеми ресурсами проекта.

Обработка аргументов

Для обработки аргументов команды Django использует argparse, которая является частью стандартной библиотеки Python. В своей команде мы должны использовать метод add_arguments.

Позиционные аргументы

Следующий пример — это команда, создающая случайных пользователей. Она принимает обязательный аргумент total, который определяет, сколько пользователей должно быть создано этой командой.

management/commands/create_users.py

from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from django.utils.crypto import get_random_string

class Command(BaseCommand):
    help = u'Создание случайного пользователя'

    def add_arguments(self, parser):
        parser.add_argument('total', type=int, help=u'Количество создаваемых пользователей')

    def handle(self, *args, **kwargs):
        total = kwargs['total']
        for i in range(total):
            User.objects.create_user(username=get_random_string(), email='', password='123')

Использование этой команды:

python manage.py create_users 10

Опциональные аргументы

Опциональные (и именованные) аргументы могут передаваться в любом порядке. В следующем примере находится определение аргумента prefix, который будет скомпонован с полем username.

management/commands/create_users.py

from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from django.utils.crypto import get_random_string

class Command(BaseCommand):
    help = 'Создание случайного пользователя'

    def add_arguments(self, parser):
        parser.add_argument('total', type=int, help='Количество создаваемых пользователей')

        # Optional argument
        parser.add_argument('-p', '--prefix', type=str, help='Префикс для username', )

    def handle(self, *args, **kwargs):
        total = kwargs['total']
        prefix = kwargs['prefix']

        for i in range(total):
            if prefix:
                username = '{prefix}_{random_string}'.format(prefix=prefix, random_string=get_random_string())
            else:
                username = get_random_string()
            User.objects.create_user(username=username, email='', password='123')

Использование:

python manage.py create_users 10 --prefix custom_user

или

python manage.py create_users 10 -p custom_user

Если указан префикс, то поле username будет, например, таким: custom_user_oYwoxtt4vNHR. Без указания префикса результат будет следующим: oYwoxtt4vNHR, т. е. просто случайная строка.

Флаговые аргументы

Один из типов необязательных аргументов — это флаг, который использует булевый тип. Давайте добавим флаг — admin, для указания команде создать суперпользователя или обычного пользователя, если флаг не указан.

management/commands/create_users.py

from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
from django.utils.crypto import get_random_string

class Command(BaseCommand):
    help = 'Create random users'

    def add_arguments(self, parser):
        parser.add_argument('total', type=int, help='Количество создаваемых пользователей')
        parser.add_argument('-p', '--prefix', type=str, help='Префикс для username')
        parser.add_argument('-a', '--admin', action='store_true', help='Создание учетной записи администратора')

    def handle(self, *args, **kwargs):
        total = kwargs['total']
        prefix = kwargs['prefix']
        admin = kwargs['admin']

        for i in range(total):
            if prefix:
                username = '{prefix}_{random_string}'.format(prefix=prefix, random_string=get_random_string())
            else:
                username = get_random_string()

            if admin:
                User.objects.create_superuser(username=username, email='', password='123')
            else:
                User.objects.create_user(username=username, email='', password='123')

Использование:

python manage.py create_users 2 --admin

Или

python manage.py create_users 2 -a

Произвольный список аргументов

Давайте создадим новую команду delete_users. В ней мы передадим список идентификаторов пользователей, которых команда должна удалить из базы данных.

management/commands/delete_users.py

from django.contrib.auth.models import User
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'Delete users'

    def add_arguments(self, parser):
        parser.add_argument('user_id', nargs='+', type=int, help='User ID')

    def handle(self, *args, **kwargs):
        users_ids = kwargs['user_id']

        for user_id in users_ids:
            try:
                user = User.objects.get(pk=user_id)
                user.delete()
                self.stdout.write(u'Пользователь"%s (%s)" удален успешно!' % (user.username, user_id))
            except User.DoesNotExist:
                self.stdout.write(u'Пользователь с id "%s" не существует.' % user_id)

Использование:

python manage.py delete_users 1

Результат:

Пользователь "SMl5ISqAsIS8 (1)" удален успешно!

Также мы можем передать список id, разделенных пробелом, таким образом команда удалит пользователей за один вызов:

python manage.py delete_users 1 2 3 4

Результат:

Пользователь с id "1" не существует.
Пользователь "9teHR4Y7Bz4q (2)" удален успешно!
Пользователь "ABdSgmBtfO2t (3)" удален успешно!
Пользователь "BsDxOO8Uxgvo (4)" удален успешно!

Стилизация

Можно улучшить предыдущий пример, добавив цвета для вывода сообщений:

management/commands/delete_users.py

from django.contrib.auth.models import User
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'Delete users'

    def add_arguments(self, parser):
        parser.add_argument('user_id', nargs='+', type=int, help='User ID')

    def handle(self, *args, **kwargs):
        users_ids = kwargs['user_id']

        for user_id in users_ids:
            try:
                user = User.objects.get(pk=user_id)
                user.delete()
                self.stdout.write(self.style.SUCCESS(u'Пользователь "%s (%s)" удален успешно!' % (user.username, user_id)))
            except User.DoesNotExist:
                self.stdout.write(self.style.WARNING(u'Пользователь с id "%s" не существует.' % user_id))

Использование:

python manage.py delete_users 3 4 5 6

Результат:

Ниже предоставлен список всех доступных стилей в виде пользовательской команды:

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'Show all available styles'

    def handle(self, *args, **kwargs):
        self.stdout.write(self.style.ERROR('error - A major error.'))
        self.stdout.write(self.style.NOTICE('notice - A minor error.'))
        self.stdout.write(self.style.SUCCESS('success - A success.'))
        self.stdout.write(self.style.WARNING('warning - A warning.'))
        self.stdout.write(self.style.SQL_FIELD('sql_field - The name of a model field in SQL.'))
        self.stdout.write(self.style.SQL_COLTYPE('sql_coltype - The type of a model field in SQL.'))
        self.stdout.write(self.style.SQL_KEYWORD('sql_keyword - An SQL keyword.'))
        self.stdout.write(self.style.SQL_TABLE('sql_table - The name of a model in SQL.'))
        self.stdout.write(self.style.HTTP_INFO('http_info - A 1XX HTTP Informational server response.'))
        self.stdout.write(self.style.HTTP_SUCCESS('http_success - A 2XX HTTP Success server response.'))
        self.stdout.write(self.style.HTTP_NOT_MODIFIED('http_not_modified - A 304 HTTP Not Modified server response.'))
        self.stdout.write(self.style.HTTP_REDIRECT('http_redirect - A 3XX HTTP Redirect server response other than 304.'))
        self.stdout.write(self.style.HTTP_NOT_FOUND('http_not_found - A 404 HTTP Not Found server response.'))
        self.stdout.write(self.style.HTTP_BAD_REQUEST('http_bad_request - A 4XX HTTP Bad Request server response other than 404.'))
        self.stdout.write(self.style.HTTP_SERVER_ERROR('http_server_error - A 5XX HTTP Server Error response.'))
        self.stdout.write(self.style.MIGRATE_HEADING('migrate_heading - A heading in a migrations management command.'))
        self.stdout.write(self.style.MIGRATE_LABEL('migrate_label - A migration name.'))

Задания для утилиты cron

Если у вас есть задачи, которые должны периодически выполняться, можно использовать свою команду и добавить ее в crontab:

# m h  dom mon dow   command
0 4 * * * /home/mysite/venv/bin/python /home/mysite/mysite/manage.py my_custom_command

Этот пример будет выполнять каждый день в 4 часа команду my_custom_command.

Поделитесь с другими:

Представления-классы
(Class-Based Views)

Детальное описание и структура классов Django.

Django: WebSocket`ы и Channels

WebSockets — это технология, которая позволяет открывать сеанс интерактивной связи между браузером пользователя и сервером. С помощью этой технологии пользователь может отправлять сообщения на сервер и получать управляемые событиями ответы, не требуя длительного опроса, то есть без необходимости постоянно проверять сервер на предмет ответа. Подумайте, когда вы отвечаете на электронное письмо в Gmail, и в нижней части экрана вы видите всплывающее предупреждение «1 непрочитанное сообщение от [...]» от человека, на которого вы только что отвечали. Такая обратная связь в режиме реального времени обусловлена такими технологиями, как WebSockets!

Выпуск Django 3.0

Команда Django рада объявить о выпуске Django 3.0: движение к тому, чтобы сделать Django полностью асинхронным, предоставляя поддержку для работы в качестве приложения ASGI, теперь официально поддерживает MariaDB 10.1 и выше, а также много других новых функций и возможностей.

Выпущены релизы безопасности Django: 2.2.8 и 2.1.15

В соответствии с политикой безопасности, команда Django выпускает Django 2.2.8 и Django 2.1.15. Этот выпуск решает проблему безопасности, подробно описанную ниже. Мы призываем всех пользователей Django обновиться как можно скорее.

Путь от request до response в Джанго

Веб-приложение или веб-сайт вращаются вокруг цикла запрос-ответ, и приложения Django не являются исключением. Но это не просто двухэтапный процесс. Наши приложения Django должны пройти различные стадии, чтобы вернуть конечному пользователю результат. Чтобы лучше понять структуру Django, мы должны понимать, как инициируются запросы и как конечный результат передается конечному пользователю. В статье объясняются различные этапы запросов и используемое там программное обеспечение или код.

Выпущен релиз-кандидат Django 3.0

Кандидат 1 релиза Django 3.0 - это последняя возможность для вас испытать множество новых функций перед выпуском Django 3.0.

Django DetailView - основы использования

Django позволяет создавать приложения очень легко. Если приложение должно быть выпущено быстро и является относительно общим, то эта среда Python идеально подходит для этого. В течение нескольких лет я профессионально работал в этой среде и часто рылся внутри, поэтому знаю почти всё, и сегодня я представлю вам все, что нужно знать, чтобы эффективно использовать универсальный DetailView в Django.

Выпущены исправления Django: 2.2.7, 2.1.14 и 1.11.26

Сегодня команда разработчиков Django выпустила версии 2.2.7, 2.1.14 и 1.11.26 с исправлениями ошибок. Пакет и контрольные суммы доступны на странице загрузок, а также из индекса пакетов Python. Идентификатор ключа PGP, использованный в этом выпуске: Mariusz Felisiak: 2EF56372BA48CD1B.

Как заставить request.is_ajax() работать с JS fetch()

Объект запроса Django request имеет изящный небольшой метод is_ajax(). Он позволяет определить, поступил ли запрос от JS-фреймворка (он же ajax старой школы). Хотя он отлично работает с некоторыми библиотеками JS, включая почтенный jQuery, он не будет работать с современным встроенным в JS fetch().

Практика программирования на Python 3, лекция №5

Лекции о Python 3 от Тимофея Хирьянова при поддержке Московского физико-технического института. Лекция №5.

Практика программирования на Python 3, лекция №4

Лекции о Python 3 от Тимофея Хирьянова при поддержке Московского физико-технического института. Лекция №4.