AndreyMelnikov.MyBlog # мой блог: IT-марафон.

Все мои посты

Django. Пользовательские команды и Пагинация.

В Django имеется функционал создания своих собственных пользовательских консольных команд для администрирования проекта.

Давайте рассмотрим пример создания такой команды, применительно к нашему учебному проекту с автопредприятиями. Наша команда будет генерировать указанное количество автомобилей применительно к предприятию (или списка предприятий), которое также будет указываться в параметрах команды.

Для этого создадим каталог management в основном каталоге проекта (на уровне каталогов static и аpi). В management создадим подкаталог commands и уже непосредственно в нем будем создавать наши команды. Для того чтобы Python учитывал каталог commands, как свой пакет, необходимо добавить пустой файл __init__.py. Для получения пользовательской команды достаточно создать питоновский файл с таким-же именем, как и у предполагаемой команды. Например, для команды генерирующей наши машинки – gencar, мы создаем gencar.py.

Создадим класс команды - Command , наследованный от класса BaseCommand, который предоставляется фреймворком:

from django.core.management.base import BaseCommand
from django.utils.crypto import get_random_string
from rest_framework.generics import get_object_or_404
from ...models import *

class Command(BaseCommand):
    # Задаём текст помощи, который будет отображён при выполнении команды
    # python manage.py gencars --help
    help = u'Generate cars. Создание моделей Car со случайным содержанием полей'

    def add_arguments(self, parser):
    # Указываем сколько и каких аргументов принимает команда.
    # В данном случае первый аргументом идет id предприятия, nargs='+' - минимум один аргумент, либо список.
    parser.add_argument('-e', '--enterprise_id', nargs='+', type=int,
                        help=u'Для какого предприятия(либо список enterprise_id через пробел)')
    # Вторым аргументом передаем число
    parser.add_argument('-n', '--number', type=int, help=u'Количество создаваемых Car')

    def handle(self, *args, **options):
        # Получаем аргументы:
        enterprise_id = options['enterprise_id']
        number_cars = options['number']
        # enterprise_id - возможно список, по этому итерируемся сначала по нему.
        for enterprise in enterprise_id:
            of_enterprise = get_object_or_404(Enterprise.objects.all(), pk=enterprise)
            # Создаем число машинок = number_cars
            for i in range(number_cars):
                brand = get_random_string() # случайная генерация строки для поля Car
                model = get_random_string()
                color = get_random_string()
                # Непосредственно, создание модели типа Car, с указанными полями
                Car.objects.create(brand=brand, model=model, color=color, fuel_util=10, of_enterprise=of_enterprise)
	self.stdout.write('Successfully created {0} cars!'.format(number_cars))
        self.stdout.write('Current list cars: {}'.format(list(Car.objects.all())))

add_arguments()- в данной функции мы определяем сколько и каких аргументов будет передано в команду. В нашем случае мы используем два параметра:

-e (enterprise), где указываем id предприятия, к которому будет привязана созданная машинка, или список id предприятий.

-n (number) – задает количество моделей для генерации (сколько машинок будет создано).

handle() – переопределяя эту функцию, мы задаем обработку переданных параметров, и дальнейшую логику действий по реализации семантики нашей команды. Все аргументы приходят в списке (options). Также в данной функции для генерации случайного текста мы использовали метод get_random_string(), импортированного из django.utils.crypto.
Далее, если мы введем в командной строке:

python manage.py gencar –e 1 –n 10

у нас создастся 10 машинок прикрепленный к предприятию с id 1.

Также мы можем создать, например, по 50 машинок для предприятия с id 1 и id 2:

python manage.py gencar –e 1 2 –n 50

Теперь у нас появилась возможность массово создавать модели Car со случайным значением полей. Но как быть с отображением? Напомню, что сейчас список объектов Car отображается вот так:


Что будет, если мы создадим, скажем, 5000 машинок? В данном случае необходимо реализовать постраничное отображение – пагинацию.

Пагинация – это разбиение на страницы или постраничная нумерация. В Django REST фреймворке есть стандартные классы для реализации данного функционала. Я опишу самый простой способ сделать это в рамках REST фреймворка.

Для начала укажем в глобальных настройках нашего проекта (settings.py) класс, который будет использоваться для пагинации по умолчанию:

REST_FRAMEWORK = {
        # глобальная настройка для стиля пагинации с указанием количества элементов на странице PAGE_SIZE
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 5,
}

'PAGE_SIZE'- определяет количество элементов на одной странице.

Далее в нашем файле с представлением (api\view.py) переопределим поле pagination_class = LimitOffsetPagination

class CarView(LoginRequiredMixin, ListCreateAPIView):
    # представление для списка авто с методами create и get
    serializer_class = CarSerializer
    pagination_class = LimitOffsetPagination

Также, необходимо добавить логику в наш метод get():

def get(self, request):
    # переопределяем родительский метод для получения запроса GET
    queryset = self.get_queryset()
    serializer = CarSerializer(queryset, many=True)
    page = self.paginate_queryset(queryset) # формируем данные для отображения на одной странице
    if page is not None:
        serializer = CarSerializer(page, many=True) # сериализуем данные page
        return self.get_paginated_response(serializer.data)
    return Response({"cars": serializer.data})

Тут мы создаем экземпляр класса нашего пагинатора, передаем ему результат запроса (queryset). Объект page – будет являться набором данных для одной страницы. Далее мы через сериализацию выводим данные.

Как можно увидеть, теперь у нас есть постраничное отображение списка Car:

Назад к списку постов