Быстрый старт

Создать новый проект, основанный на фреймворке VST Utils, довольно просто. Мы рекомендуем создавать виртуальное окружение отдельно для каждого из ваших проектов, чтобы избежать конфликтов в системе.

Давайте учиться на примерах. Все что вам нужно сделать это запустить несколько команд. Этот мануал состоит из двух частей:

  1. Описание процесса создания нового приложения и основных команд для запуска и развертывания.

  2. Описание процесса создания новых сущностей в приложении.

Создание нового приложения

В этом руководстве мы создадим базовое приложение.

  1. Установка VST Utils

    pip install vstutils
    

    В данном случае мы устанавливаем пакет с минимальным набором зависимостей для создания новых проектов. Однако, внутри проекта используется специальный аргумент prod который дополнительно устанавливает все пакеты, необходимые для работы в окружении для развертывания. Также имеется набор зависимостей для тестирования, в котором содержится все, что нужно для тестирования и анализа покрытия кода.

    Также стоит отметить дополнительно зависимости, такие как:

    • rpc - установка зависимостей для выполнения асинхронных задач

    • ldap - набор зависимостей для поддержки авторизации ldap

    • doc - все, что нужно для построения документации и осуществления доставки документации на запущенный сервер

    • pil - библиотека для корректной работы валидации изображений

    • boto3 - дополнительный набор зависимостей для работы с S3 хранилищем вне AWS

    • sqs - набор зависимостей для соединения асинхронных задач с SQS очередями (может использоваться вместо rpc).

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

    pip install vstutils[prod,rpc,boto3]
    

    Чтобы установить наиболее полный набор зависимостей, вы можете использовать обычный параметр all.

    pip install vstutils[all]
    
  2. Создание нового проекта, основанного на VST Utils

    Если вы впервые используете vstutils, вам нужно позаботиться о начальной настройке. А именно: вам необходимо будет автоматически сгенерировать код, создающий приложение vstutils, включая конфигурацию базы данных, специфичные опции для Django и vstutils, а также настройки, специфичные для приложения. Для создания нового проекта выполните следующую команду:

    python -m vstutils newproject --name {{app_name}}
    

    Эта команда предложит указать такие параметры нового приложения, как:

    • project name - имя вашего нового приложения;

    • project guiname - имя вашего нового приложения, которое будет использоваться в GUI(веб-интерфейсе);

    • project directory - путь к директории, в которой будет создан проект.

    Или вы можете выполнить следующую команду, которая содержит всю необходимую информацию для создания нового проекта.

    python -m vstutils newproject --name {{app_name}} --dir {{app_dir}} --guiname {{app_guiname}} --noinput
    

    Эта команда создает новый проект без подтверждения какой-либо информации.

    Эти команды создают несколько файлов в project directory:

    /{{app_dir}}/{{app_name}}
     ├── frontend_src
     │   ├── app
     │   │   └── index
     │   ├── .editorconfig
     │   ├── .eslintrc.js
     │   └── .prettierrc
     ├── MANIFEST.in
     ├── package.json
     ├── README.rst
     ├── requirements-test.txt
     ├── requirements.txt
     ├── pyproject.toml
     ├── setup.py
     ├── {{app_name}}
     │   ├── __init__.py
     │   ├── __main__.py
     │   ├── models
     │   │   └── __init__.py
     │   ├── settings.ini
     │   ├── settings.py
     │   ├── web.ini
     │   └── wsgi.py
     ├── test.py
     ├── tox.ini
     └── webpack.config.jsdefault
    

    где

    • frontend_src - директория, содержащая все исходные файлы для фронтенда;

    • MANIFEST.in - этот файл используется для создания установочного пакета;

    • {{app_name}} - директория с файлами вашего приложения;

    • package.json - этот файл содержит список зависимостей фронтенда и команд для сборки;

    • README.rst - стандартный README файл для вашего приложения (этот файл включает базовые команды для запуска/остановки вашего приложения);

    • requirements-test.txt - файл со списком зависимостей для тестирования вашего окружения;

    • requirements.txt - файл со списком зависимостей вашего приложения;

    • pyproject.toml - файл, используемый для сборки установочного пакета;

    • setup.py - файл, используемый для сборки установочного пакета;

    • test.py - этот файл используется для создания тестов;

    • tox.ini - этот файл используется для выполнения тестов;

    • webpack.config.js.default - этот файл содержит минимальный скрипт для webpack (замените „.default“, если пишите что-то в „app.js“).

    Вам нужно выполнять приведенные ниже команды из директории /{{app_dir}}/{{app_name}}/. Хорошей практикой будет использование tox (должен быть установлен перед использованием) для создания отладочной среды для вашего приложения. Для этих целей рекомендуется использовать tox -e contrib в директории проекта, что автоматически создаст новое окружение с необходимыми зависимостями.

  3. Применение миграций

    Давайте проверим, работает ли новый проект vstutils. Перейдите во внешний каталог /{{app_dir}}/{{app_name}}, если вы еще этого не сделали, и выполните следующую команду:

    python -m {{app_name}} migrate
    

    Эта команда создаст базу данных SQLite (по умолчанию) с SQL схемой по умолчанию. VSTUTILS поддерживает все базы данных которые поддерживает Django.

  4. Создание суперпользователя

    python -m {{app_name}} createsuperuser
    
  5. Запуск приложения

    python -m {{app_name}} web
    

    Веб-интерфейс вашего приложения будет запущен на порту 8080. Вы запустили сервер vstutils для продакшена на основе uWSGI.

    Предупреждение

    Сейчас хорошее время отметить: если вы хотите запустить веб-сервер с отладчиком, то вам следует запустить стандартный сервер разработки Django <https://docs.djangoproject.com/en/3.2/intro/tutorial01/#the-development-server>`_

    _images/app_example_login_page.png

    Если вам нужно остановить сервер, используйте следующую команду:

    python -m {{app_name}} web stop=/tmp/{{app_name}}_web.pid
    

Вы создали простейшее приложение, основанное на фреймворке VST Utils. Это приложение содержит только модель пользователя. Если вы хотите создать свои собственные модели, обратитесь к разделу ниже.

Добавление новых моделей в приложение

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

  1. Создайте модель;

  2. Создайте сериализатор (опционально);

  3. Создайте view (опционально);

  4. Добавьте созданную модель или view в API;

  5. Создайте миграции;

  6. Примените миграции;

  7. Перезапустите ваше приложение.

Давайте посмотрим, как это можно сделать на примере приложения AppExample которое содержит 2 пользовательские модели:

  • Task (абстракция для некоторых задач/активностей, которые пользователь должен выполнить);

  • Stage (абстракция для некоторых этапов, которые пользователь должен пройти для выполнения задачи. Эта модель вложена в модель Task).

Создание моделей

Сначала вам необходимо создать файл {{model_name}}.py в директории /{{app_dir}}/{{app_name}}/{{app_name}}/models.

Давайте рассмотрим пример с моделью BModel:

class vstutils.models.BModel(*args, **kwargs)[исходный код]

Класс модели по умолчанию, который генерирует viewset, отдельные сериализаторы для list() и retrieve(), фильтры, эндпоинты API и вложенные view

Примеры:
from django.db import models
from rest_framework.fields import ChoiceField
from vstutils.models import BModel

class Stage(BModel):
    name = models.CharField(max_length=256)
    order = models.IntegerField(default=0)

    class Meta:
        default_related_name = "stage"
        ordering = ('order', 'id',)
        # fields which would be showed on list.
        _list_fields = [
            'id',
            'name',
        ]
        # fields which would be showed on detail view and creation.
        _detail_fields = [
            'id',
            'name',
            'order'
        ]
        # make order as choices from 0 to 9
        _override_detail_fields = {
            'order': ChoiceField((str(i) for i in range(10)))
        }


class Task(BModel):
    name = models.CharField(max_length=256)
    stages = models.ManyToManyField(Stage)
    _translate_model = 'Task'

    class Meta:
        # fields which would be showed.
        _list_fields = [
            'id',
            'name',
        ]
        # create nested views from models
        _nested = {
            'stage': {
                'allow_append': False,
                'model': Stage
            }
        }

В данном случае вы создаете модели, которые могут быть преобразованы в простое view, где:

  • POST/GET по адресу /api/version/task/ - создает новую задачу или получает список задач

  • PUT/PATCH/GET/DELETE по адресу /api/version/task/:id/ - обновляет, извлекает или удаляет экземпляр задачи

  • POST/GET по адресу /api/version/task/:id/stage/ - создает новую или получает список стадий в задаче

  • PUT/PATCH/GET/DELETE по адресу /api/version/task/:id/stage/:stage_id - обновляет, извлекает или удаляет экземпляр стадии в задаче.

Для привязки view к API вставьте следующий код в файл settings.py:

API[VST_API_VERSION][r'task'] = {
    'model': 'your_application.models.Task'
}

Для основного доступа к сгенерированному view унаследуйтесь от свойства Task.generated_view.

Чтобы упростить перевод на фронтенде используйте атрибут _translate_model с model_name

Список мета-атрибутов для создания view:

  • _view_class - список дополнительных классов view для наследования, класс или строка для импорта с базовым классом viewSet. Также поддерживаются константы:

    • read_only - для создания view только для просмотра;

    • list_only - для создания view только со списком;

    • history - для создания view только для просмотра и удаления записей

    CRUD-view применяется по умолчанию.

  • _serializer_class - класс сериализатора API; используйте этот атрибут, чтобы указать родительский класс для автоматически создаваемых сериализаторов. По умолчанию используется vstutils.api.serializers.VSTSerializer. Может принимать строку для импорта, класс сериализатора или django.utils.functional.SimpleLazyObject.

  • _serializer_class_name - имя модели для определений OpenAPI. Это будет имя модели в сгенерированном интерфейсе администратора. По умолчанию используется имя класса модели.

  • _list_fields или _detail_fields - список полей, которые будут перечислены списке сущностей или детальном view соответственно. То же самое, что и мета-атрибут «fields» сериализаторов DRF.

  • _override_list_fields или _override_detail_fields - отображение с именами и типами полей, которые будут переопределены в атрибутах сериализатора (рассматривайте это как объявление полей в сериализаторе DRF ModelSerializer).

  • _properties_groups - словарь с ключом в виде имени группы и значением в виде списка полей (строк). Позволяет группировать поля в разделы на фронтенде.

  • _view_field_name - имя поля, которое фронтенд показывает в качестве основного имени view.

  • _non_bulk_methods - список методов, которые не должны использоваться через пакетные запросы.

  • _extra_serializer_classes - отображение с дополнительными сериализаторами в viewset. Например, пользовательский сериализатор, который будет вычислять что-то в действии (имя отображения). Значение может быть строкой для импорта. Важное замечание: установка атрибута модели в None позволяет использовать стандартный механизм создания сериализатора и получать поля из сериализатора списка или детальной записи (установите __inject_from__ мета-атрибут сериализатора в list или detail соответственно). В некоторых случаях требуется передать модель в сериализатор. Для этого можно использовать константу LAZY_MODEL в качестве мета-атрибута. Каждый раз при использовании сериализатора будет установлена точная модель, в которой был объявлен этот сериализатор.

  • _filterset_fields - список/словарь имен фильтров для фильтрации API. По умолчанию это список полей в view списке. При обработке списка полей проверяется наличие специальных имен полей и наследуются дополнительные родительские классы. Если список содержит id, класс будет наследоваться от vstutils.api.filters.DefaultIDFilter. Если список содержит name, класс будет наследоваться от vstutils.api.filters.DefaultNameFilter. Если присутствуют оба условия, наследование будет происходить от всех вышеперечисленных классов. Возможные значения включают список (list) полей для фильтрации или словарь (dict), где ключ - это имя поля, а значение - класс Filter. Словарь расширяет функциональность атрибута и позволяет переопределять класс поля фильтра (значение None отключает переопределение).

  • _search_fields - кортеж или список полей, используемых для поисковых запросов. По умолчанию (или None) получаются все поля, по которым можно фильтровать в детальном view.

  • _copy_attrs - список атрибутов экземпляра модели, указывающих, что объект можно скопировать с этими атрибутами.

  • _nested - сопоставление ключ-значение вложенных view (ключ - имя вложенного view, kwargs для декоратора vstutils.api.decorators.nested_view, но поддерживает атрибут model в качестве вложенного). model может быть строкой для импорта. Используйте параметр override_params в тех случаях, когда необходимо перегрузить параметры генерируемого представления в качестве вложенного (работает только когда задан model как вложенное представление).

  • _extra_view_attributes - отображение ключ-значение с дополнительными атрибутами view, но имеет меньший приоритет перед сгенерированными атрибутами.

Также вы также можете добавлять пользовательские атрибуты для переопределения или расширения списка обрабатываемых классов по умолчанию. Поддерживаемые атрибуты view: filter_backends, permission_classes, authentication_classes, throttle_classes, renderer_classes и parser_classes. Список мета-атрибутов для настроек view выглядит следующим образом:

  • _pre_{attribute} - список классов, включаемых перед значениями по умолчанию.

  • _{attribute} - список классов, включаемых после значений по умолчанию.

  • _override_{attribute} - флаг-булево значение, указывающее, переопределяет ли атрибут view по умолчанию (в противном случае добавляется). По умолчанию False.

Примечание

Возможно, вам понадобится создать action в сгенерированном view. Используйте декоратор vstutils.models.decorators.register_view_action с аргументом detail, чтобы определить применимость к списку или детальной записи. В этом случае декорированный метод будет принимать объект view в качестве атрибута self.

Примечание

В некоторых случаях при наследовании моделей может потребоваться наследовать класс Meta от базовой модели. Если Meta явно объявлена в базовом классе, вы можете получить ее через атрибут OriginalMeta и использовать для наследования.

Примечание

Docstring модели будет использоваться для описания view. Можно написать как общее описание для всех действий, так и описание для каждого действия, используя следующий синтаксис:

General description for all actions.

action_name:
    Description for this action.

another_action:
    Description for another action.

Метод get_view_class() — это служебный метод в ORM Django моделях, предназначенный для облегчения настройки и создания экземпляров представлений Django Rest Framework (DRF). Это позволяет разработчикам определить и настроить различные аспекты класса представления DRF.

Примеры:
# Create simple list view with same fields
TaskViewSet = Task.get_view_class(view_class='list_only')

# Create view with overriding nested view params
from rest_framework.mixins import CreateModelMixin

TaskViewSet = Task.get_view_class(
    nested={
        "milestones": {
            "model": Stage,
            "override_params": {
                "view_class": ("history", CreateModelMixin)
            },
        },
    },
)

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

Более подробную информацию о моделях вы можете найти в документации Django Models.

Если вам не нужно создавать пользовательские сериализаторы или view sets, вы можете перейти к этому этапу.

Создание сериализаторов

Примечание - Если вам не нужен пользовательский сериализатор, вы можете пропустить этот раздел.

В первую очередь вам необходимо создать файл serializers.py в директории /{{app_dir}}/{{app_name}}/{{app_name}}/.

Затем вам нужно добавить некоторый код, подобный следующему, в файл serializers.py:

from datetime import datetime
from vstutils.api import serializers as vst_serializers
from . import models as models

class StageSerializer(models.Stage.generated_view.serializer_class):

    class Meta:
        model = models.Stage
        fields = ('id',
                'name',
                'order',)

    def update(self, instance, validated_data):
        # Put custom logic to serializer update
        instance.last_update = datetime.utcnow()
        super().update(instance, validated_data)

Более подробную информацию о сериализаторах вы можете найти в документации Django REST Framework по сериализаторам.

Создание views

Примечание - Если вам не нужен пользовательский view set, вы можете пропустить этот раздел.

В первую очередь вам необходимо создать файл views.py в директории /{{app_dir}}/{{app_name}}/{{app_name}}/.

Затем вам нужно добавить некоторый код, подобный следующему, в файл views.py:

from vstutils.api import decorators as deco
from vstutils.api.base import ModelViewSet
from . import serializers as sers
from .models import Stage, Task


class StageViewSet(Stage.generated_view):
    serializer_class_one = sers.StageSerializer


'''
Decorator, that allows to put one view into another
    * 'tasks' - suburl for nested view
    * 'methods=["get"]' - allowed methods for this view
    * 'manager_name='hosts' - Name of related QuerySet to the child model instances (we set it in HostGroup model as "hosts = models.ManyToManyField(Host)")
    *  'view=Task.generated_view' - Nested view, that will be child view for decorated view
'''
@nested_view('stage', view=StageViewSet)
class TaskViewSet(Task.generated_view):
    '''
    Task operations.
    '''

Больше информации о view и viewset вы можете найти в документации Django REST Framework для view.

Добавление моделей в API

Для добавления моделей в APi вам нужно написать код, подобный этому в в конце файла settings.py:

'''
Some code generated by VST Utils
'''

'''
Add Task view set to the API
Only 'root' (parent) views should be added there.
Nested views added automatically, that's why there is only Task view.
Stage view is added altogether with Task as nested view.
'''
API[VST_API_VERSION][r'task'] = {
    'view': 'newapp2.views.TaskViewSet'
}

'''
You can add model too.
All model generate base ViewSet with data that they have, if you don't create custom ViewSet or Serializer
'''
API[VST_API_VERSION][r'task'] = dict(
    model='newapp2.models.Task'
)

# Adds link to the task view to the GUI menu
PROJECT_GUI_MENU.insert(0, {
    'name': 'Task',
     # CSS class of font-awesome icon
    'span_class': 'fa fa-list-alt',
    'url': '/task'
})

Создание миграций

Для создания миграций откройте директорию /{{app_dir}}/{{app_name}}/ и выполните следующую команду:

python -m {{app_name}} makemigrations {{app_name}}

Более подробную информацию о миграциях вы можете найти в документации Django Migrations.

Применение миграций

Для применения миграций вам необходимо открыть директорию /{{app_dir}}/{{app_name}}/ и выполнить следующую команду:

python -m {{app_name}} migrate

Перезапуск приложения

Для перезапуска вашего приложения вам сначала нужно остановить его (если оно было запущено ранее):

python -m {{app_name}} web stop=/tmp/{{app_name}}_web.pid

Затем запустите его снова:

python -m {{app_name}} web

После перезагрузки кэша вы увидите следующую страницу:

_images/app_example_home_page.png

Как вы можете видеть, ссылка на новое Task view добавлена в боковое меню. Давайте нажмем на нее.

_images/app_example_task_empty_list_page.png

В вашем приложении нет экземпляра задачи. Добавьте его, используя кнопку „new“.

_images/app_example_new_task_page.png

После создания новой задачи вы увидите следующую страницу:

_images/app_example_created_task_page.png

Как видите, есть кнопка „stages“, которая открывает страницу со списком этапов этой задачи. Давайте на нее нажмем.

_images/app_example_stage_empty_list_page.png

В вашем приложении нет экземпляров этапов. Давайте создадим 2 новых этапа.

_images/app_example_new_stage2_page.png _images/app_example_new_stage1_page.png

После создания этапов страница со списком этапов будет выглядеть так:

_images/app_example_stage_list_page.png

Сортировка по полю order работает, как мы указали в нашем файле models.py для модели Stage.

Дополнительную информацию о Django и Django REST Framework вы можете найти в документации Django и документации Django REST Framework.