platform-doc

django-report-api


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

Библиотека позволяет создавать API для формирования универсальных отчетов по любым моделям.

Создание отчета происходит путем создания виртуальной таблицы запросом SQLAlchemy. Структура данных описывается моделью Django.

Универсальный механизм отчетов предоставляет возможности:

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


Для того чтобы использовать django-report-api достаточно произвести установку пакета, и необходимых настроек, после чего необходимо подключить создать и подключить модели отчетов для которых хотим создать универсальный API: При этом, у модели должен присутствовать метод get_report_query содержащий логику получения запроса с данными.

../models.py

from django_report_api.models import BaseReportModel

class ReportModelName(BaseReportModel):
    ... 
    class Meta:
        abstract = True

    def get_report_query(self):
        return Запрос SQLAlchemy
...

../urls.py

from ... import ReportModelName, ...
from django_report_api.report_router import router

router.register(ReportModelName)

...
Универсальный механизм отчетов со всеми возможностями описанными [выше](#main) готов! ---

Требования


  1. Python (3.9)
  2. Django (3.1)
  3. Django REST framework (3.12)
  4. django-rest-witchcraft (0.12)
  5. aldjemy (2.6)
  6. SQLAlchemy (1.4)

(Рекомендуется совместное использование с библиотекой ADAPI)


Установка


Установка с использованием pip(рекомендуется)…

$ pip install git+https://<PERSONAL ACCESS TOKEN>@github.com/Digitatl/django-report-api.git

Или из источника...

$ git clone https://github.com/Digitatl/django-report-api.git
$ cd adapi
$ pip install -e . ---

Настройки


Необходимые настройки settings.INSTALLED_APPS.

INSTALLED_APPS = [
...
'rest_framework',
'aldjemy',
'django_report_api',
...
    ]

Примеры

Выбор полей в ответе

Выбрать какие поля будут содержаться в ответе можно с помощью параметра параметр fields Например, Вам нужен список пользователей, но вас интересуют только поля “id” и “username”:

GET /users/?fields=id,username
  [ 
    { 
    "id": 1, 
    "username": "user1" 
    }, 
    { 
    "id": 2, 
    "username": "user2" 
    } 
  ] ### <a name="group_by_report"></a> Группировка результатов с расчетом агрегатных функций Группировка позволяет "свернуть" таблицу по указанным в параметре group_by полям.

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

GET /product/?fields=name,number_of_sales__sum&group_by=name

  [ 
    { 
    "name": "Утюг", 
    "number_of_sales__sum": 100 
    }, 
    { 
    "name": "Репа", 
    "number_of_sales__sum": 400 
    } 
  ]

Итоги отчетов

Позволяет вычислить итоги по одним полям в разрезе других полей.

Отчет может быть:

Без итогов отчет представляет собой список всех полученных записей.

При расчете итогов формируется отчет с иерархической структурой в формате, представленном ниже.

{'results': Общие итоги,
'children': [{'results': Итоги по группе 1, 'children': [Записи принадлежащие группе 1]},
             {'results': Итоги по группе 2, 'children': [Записи принадлежащие группе 2]}, ...]}

По умолчанию итоги рассчитываются только для групп. Для того чтобы дополнительно получить общие итоги, в параметр запроса results_by необходимо передать параметр OVERALL.

Для получения итогов, необходимо передать в параметр results имя поля(полей) с указанием агрегатной функции. И в параметр results_by передать поля по которым необходима группировка для вычисления групповых итогов. (И/ИЛИ опциональный параметр OVERALL)

Рассмотрим пример: Вам нужен список организаций, с общей выделенной для них суммой и групповыми итогами по типу организации общими итогами:

GET /organizations/?results=amount__sum&results_by=type,OVERALL

  {'value__sum': 32.0, 'type': [{'type': 'ВУЗ', 'value__sum': 6.0,
                                          'explanation': [{'id': 1, 'value': 1.0, 'name': 'ВУЗ 1'},
                                                          {'id': 2, 'value': 2.0, 'name': 'ВУЗ 2'},
                                                          {'id': 3, 'value': 3.0, 'name': 'ВУЗ 3'}]},
                                {'type': 'ДЦ', 'value__sum': 13.0,
                                          'explanation': [{'id': 7, 'value': 6.0, 'name': 'ВУЗ 4'},
                                                          {'id': 8, 'value': 7.0, 'name': 'ВУЗ 5'}]},
                               ]}

В иерархии

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

Для получения итогов, необходимо передать в параметр in_hierarchy id объекта. Рассмотрим пример: Вам нужен список организаций, подчиненных (по полю parent) головной организации с id=1 и саму головную организацию:

GET /organizations/?in_hierarchy=1

   [{'id': 8, 'name': 'ВУЗ 4', 'parent': 4}, 
    {'id': 7, 'name': 'ВУЗ 3', 'parent': 4}, 
    {'id': 4, 'name': 'ВУЗ 2', 'parent': 1}, 
    {'id': 1, 'name': 'ВУЗ 1', 'parent': None}]

Фильтрация отчетов

Фильтры для отчета можно установить составив выражение(я), в соответствии с синтаксисом.

[ИмяПоля] [Оператор выражения] [Значение]

Возможные значения Операторов выражения перечислены в таблице ниже.

Оператор выражения Псевдоним Интерпретация Field type requirements
== eq равно -
!= not eq не равно -
< lt меньше, чем -
> gt больше чем -
<= lte меньше или равно -
>= gte больше или равно -
contains   поиск подстроки (с учетом регистра) Только для текстовых полей
in   В заданном списке -
icontains   поиск подстроки (без учета регистра) Только для текстовых полей
isnull   значение должно быть NULL -

Так же можно комбинировать несколько фильтров с помощью логических операторов and и or.

Примеры запросов

Описание Фильтр
Пустой фильтр  
Соответствие целочисленному полю age == 32
Совпадение со значениями NULL field_name isnull True
Совпадение со значениями, отличными от NULL field_name isnull False
Связать несколько фильтров с помощью «and» name = ‘Иннокентий’ and age >= 100
Связать несколько фильтров с помощью “or” name = ‘Иннокентий’ or name = ‘Терентий’
Сопоставить имя поля, чтобы оно содержало подстроку “МЭИ” name contains ‘МЭИ’

Поиск

Поиск по текстовым полям можно установить с помощью параметра (search).

/example/?search=организац

Сортировка

Сортировку можно установить с помощью параметра (sort).

/example/?sort=id

Вложенные объекты

Получение ответа с вложенными полями вынесенными в отдельную секцию можно получить задав параметр include. Вложенные объекты можно получить из секции include по ключам соответствующим наименованиям объектов(параметр related_model_name в OPTIONS запросе).

Для случая, когда необходимо вынести в отдельную секцию все объекты ссылочного типа, необходимо в параметре запроса include установить значение all. Но, если Вам нужно вынести в секцию include только одно/несколько вложенных полей, то в параметре include необходимо перечислить эти поля. Например, Вам нужен список статей(articles) и список комментариев к каждой статье:

      /articles?include=comments — запрашиваем статью с комментариями

      "results":
      {
      "data":
          [
              {
              "id": 1
              "title": "Статья 1"
              "author": "Автор 1"
              "comments": "1"
              },
              {
              "id": 2
              "title": "Статья 1"
              "author": "Автор 1"
              "comments": "2"
              },
              {
              "id": 3
              "title": "Статья 2"
              "author": "Автор 2"
              "comments": "3"
              }
          ]
      "include":
          {
          "Comments": 
              [
                  {
                  "id":1
                  "title": Комментарий 1
                  },
                  {
                  "id":2
                  "title": Комментарий 2
                  },
                  {
                  "id":3
                  "title": Комментарий 3
                  }
              ]
          }
      }

Для получения вложенных объектов глубиной более чем 1 уровень, необходимо в параметре include указать вложенные поля с разделителем - точкой. Например, include=comments.theme - получаем во вложенной секции объекты темам комментариев.

Модель отчета

В качестве модели для отчета рекомендуется использование абстрактной модели унаследованной от класса BaseReportModel.

Добавление виртуальных полей

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

Для добавления виртуальных полей в модель отчета, необходимо использовать параметр virtual_fields в метаклассе модели. Параметр virtual_fields содержит список объектов VirtualFields, которые являются наследниками NamedTuple и имеют следующие параметры:

После добавления виртуальных полей в модель, они могут быть использованы как обычные поля для построения отчетов и запросов к данным.

Возможность дополнения нулями

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

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

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