Skip to content

Commit

Permalink
Feature(backend): Add support for x-display-list for serializers.
Browse files Browse the repository at this point in the history
### Changelog:
* Feature(backend): Add support for ``x-display-list`` for serializers.
* Fix(backend): Raise ```ImproperlyConfigured``` on invalid arguments in fields.

WIP: vst/vst-utils#650+

See merge request vst/vst-utils!662
  • Loading branch information
onegreyonewhite committed Aug 13, 2024
2 parents af8e2a6 + 8aff883 commit 6081d02
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ build:
- libasound2
tools:
python: "3.11"
nodejs: "18"
nodejs: "20"
jobs:
pre_create_environment:
- npm install -g yarn @mermaid-js/mermaid-cli
Expand Down
2 changes: 1 addition & 1 deletion doc/backend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Serializers
~~~~~~~~~~~

.. automodule:: vstutils.api.serializers
:members: DisplayMode,BaseSerializer,VSTSerializer,EmptySerializer,JsonObjectSerializer
:members: DisplayMode,DisplayModeList,BaseSerializer,VSTSerializer,EmptySerializer,JsonObjectSerializer

Views
~~~~~
Expand Down
163 changes: 152 additions & 11 deletions doc/locale/ru/LC_MESSAGES/backend.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: VST Utils 5.0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-30 08:17+0000\n"
"POT-Creation-Date: 2024-08-09 05:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.15.0\n"
"Generated-By: Babel 2.16.0\n"

#: ../../backend.rst:2
msgid "Backend API manual"
Expand Down Expand Up @@ -559,6 +559,8 @@ msgstr ""
#: vstutils.api.filter_backends.VSTFilterBackend:22
#: vstutils.api.filters.FkFilterHandler:15
#: vstutils.api.serializers.BaseSerializer:12
#: vstutils.api.serializers.DisplayMode:5
#: vstutils.api.serializers.DisplayModeList:6
#: vstutils.api.serializers.VSTSerializer:10
#: vstutils.middleware.AsyncBaseMiddleware:41
#: vstutils.middleware.BaseMiddleware:38
Expand Down Expand Up @@ -748,7 +750,8 @@ msgstr "is_sliced (bool): Булево значение, указывающее,
#: vstutils.utils.classproperty vstutils.utils.create_view
#: vstutils.utils.decode vstutils.utils.deprecated vstutils.utils.encode
#: vstutils.utils.get_render vstutils.utils.lazy_translate
#: vstutils.utils.list_to_choices vstutils.utils.send_template_email
#: vstutils.utils.list_to_choices vstutils.utils.raise_misconfiguration
#: vstutils.utils.send_template_email
#: vstutils.utils.send_template_email_handler vstutils.utils.tmp_file
#: vstutils.utils.tmp_file.write vstutils.utils.translate
msgid "Parameters"
Expand Down Expand Up @@ -780,8 +783,8 @@ msgstr "Объект, содержащий параметры фильтраци
#: vstutils.utils.ObjectHandlers.backend vstutils.utils.URLHandlers.get_object
#: vstutils.utils.check_request_etag vstutils.utils.decode
#: vstutils.utils.encode vstutils.utils.get_render
#: vstutils.utils.list_to_choices vstutils.utils.send_template_email_handler
#: vstutils.utils.tmp_file.write
#: vstutils.utils.list_to_choices vstutils.utils.raise_misconfiguration
#: vstutils.utils.send_template_email_handler vstutils.utils.tmp_file.write
msgid "Returns"
msgstr "Возвращает"

Expand Down Expand Up @@ -817,13 +820,15 @@ msgstr "Генератор, возвращающий запрошенные да
#: vstutils.utils.ModelHandlers.get_object
#: vstutils.utils.ObjectHandlers.backend vstutils.utils.URLHandlers.get_object
#: vstutils.utils.create_view vstutils.utils.decode vstutils.utils.encode
#: vstutils.utils.get_render vstutils.utils.tmp_file.write
#: vstutils.utils.get_render vstutils.utils.raise_misconfiguration
#: vstutils.utils.tmp_file.write
msgid "Return type"
msgstr "Тип возвращаемого значения"

#: of vstutils.api.validators.RegularExpressionValidator
#: vstutils.models.custom_model.ExternalCustomModel.get_data_generator
#: vstutils.models.custom_model.ViewCustomModel.get_view_queryset
#: vstutils.utils.raise_misconfiguration
msgid "Raises"
msgstr "Выбрасывает"

Expand Down Expand Up @@ -2612,6 +2617,16 @@ msgstr ""
"предоставлен, будет использован :class:`.VSTCharField` для каждого поля "
"из списка `fields`."

#: of vstutils.api.fields.RelatedListField:30
msgid ""
"This field is deprecated. Use serializers with the ``many=True`` "
"attribute. To change the display on the page, use "
":const:`vstutils.api.serializers.DisplayModeList`."
msgstr ""
"Это поле устарело. Используйте сериализаторы с атрибутом ``many=True``. "
"Чтобы изменить отображение на странице, используйте "
":const:`vstutils.api.serializers.DisplayModeList`."

#: of vstutils.api.fields.SecretFileInString:1
msgid ""
"This field extends :class:`.FileInStringField` but hides its value in the"
Expand Down Expand Up @@ -2974,11 +2989,37 @@ msgstr ""

#: of vstutils.api.serializers.DisplayMode:1
msgid ""
"For any serializer displayed on frontend property `_display_mode` can be "
"set to one of this values."
"Enumeration for specifying how a serializer should be displayed on the "
"frontend."
msgstr ""
"Перечисление для указания того, как сериализатор должен отображаться на "
"фронтенде."

#: of vstutils.api.serializers.DisplayMode:3
msgid ""
"This class is used to set the ``_display_mode`` property in a serializer "
"to control its UI behavior."
msgstr ""
"Этот класс используется для установки свойства ``_display_mode`` в сериализаторе "
"для управления его поведением в пользовательском интерфейсе."

#: of vstutils.api.serializers.DisplayMode:7
msgid "To set the display mode to steps:"
msgstr "Чтобы установить режим отображения в виде последовательных шагов:"

#: of vstutils.api.serializers.DisplayMode:15
msgid "To use the default display mode:"
msgstr "Чтобы использовать режим отображения по умолчанию:"

#: of vstutils.api.serializers.DisplayMode:23
msgid ""
"Using `DisplayMode` allows developers to customize the interface based on"
" the workflow needs, making forms and data entry more user-friendly and "
"intuitive."
msgstr ""
"Для любого сериализатора, показанного на фронтенде, аттрибут "
"`_display_mode` может принимать одно из следующих значений."
"Использование `DisplayMode` позволяет разработчикам настраивать интерфейс в соответствии с "
"потребностями рабочего процесса, делая формы и ввод данных более удобными и "
"интуитивно понятными."

#: ../../docstring of vstutils.api.serializers.DisplayMode.DEFAULT:1
msgid "Will be used if no mode provided."
Expand All @@ -2992,6 +3033,55 @@ msgstr ""
"Каждая группа параметров отображается на раздельных вкладках. При "
"создании выглядит как пошаговый мастер."

#: of vstutils.api.serializers.DisplayModeList:1
msgid ""
"Enumeration for specifying how a list serializer should be displayed on "
"the frontend."
msgstr ""
"Перечисление для указания того, как сериализатор списка должен отображаться на "
"фронтенде."

#: of vstutils.api.serializers.DisplayModeList:3
msgid ""
"This class is used to set the ``_display_mode_list`` property in a list "
"serializer to control its UI behavior when dealing with multiple "
"instances."
msgstr ""
"Этот класс используется для установки свойства ``_display_mode_list`` в сериализаторе списка "
"для управления его поведением в пользовательском интерфейсе при работе с несколькими "
"экземплярами."

#: of vstutils.api.serializers.DisplayModeList:8
msgid "To set the list display mode to table view:"
msgstr "Чтобы установить режим отображения списка в виде таблицы:"

#: of vstutils.api.serializers.DisplayModeList:20
msgid ""
"To use the default list display mode ensure that class doesn't have "
"``_display_mode_list`` class property or set value to "
"``DisplayModeList.DEFAULT``."
msgstr ""
"Чтобы использовать режим отображения списка по умолчанию, убедитесь, что класс не содержит "
"свойства ``_display_mode_list`` или установите значение в "
"``DisplayModeList.DEFAULT``."

#: of vstutils.api.serializers.DisplayModeList:23
msgid ""
"`DisplayModeList` enables developers to tailor the appearance of list "
"serializers, ensuring that users can interact with multiple data entries "
"effectively in the interface."
msgstr ""
"`DisplayModeList` позволяет разработчикам настраивать внешний вид сериализаторов списка, "
"обеспечивая эффективное взаимодействие пользователей с несколькими записями данных в интерфейсе."

#: ../../docstring of vstutils.api.serializers.DisplayModeList.DEFAULT:1
msgid "It will be displayed as a standard list of JSON objects."
msgstr "Будет отображаться как стандартный список объектов JSON."

#: ../../docstring of vstutils.api.serializers.DisplayModeList.TABLE:1
msgid "It will be displayed as a table view."
msgstr "Будет отображаться в виде таблицы."

#: of vstutils.api.serializers.EmptySerializer:1
msgid ""
"Default serializer for empty responses. In generated GUI this means that "
Expand Down Expand Up @@ -3316,7 +3406,9 @@ msgstr "Флаг, разрешающий добавление существую

#: of vstutils.api.decorators.nested_view:21
msgid "Flag for forbidding bulk queries in related manager add method."
msgstr "Флаг, запрещающий выполнение bulk запросов в методе add связанного менеджера."
msgstr ""
"Флаг, запрещающий выполнение bulk запросов в методе add связанного "
"менеджера."

#: of vstutils.api.decorators.nested_view:23
msgid "Name of model-object attr which contains nested queryset."
Expand Down Expand Up @@ -5826,6 +5918,55 @@ msgstr "Контекст для игнорирования исключений.
msgid "Context for exclude errors and return default value."
msgstr "Контекст для предотвращения исключений и возврата значения по умолчанию."

#: of vstutils.utils.raise_misconfiguration:1
msgid ""
"Helper function that raises an `ImproperlyConfigured` exception if a "
"condition is not met."
msgstr ""
"Вспомогательная функция, которая вызывает исключение "
"`ImproperlyConfigured`, если условие не выполнено."

#: of vstutils.utils.raise_misconfiguration:3
msgid ""
"This function acts as a replacement for the `assert` statement, providing"
" clearer error handling in cases where the application configuration is "
"incorrect."
msgstr ""
"Эта функция заменяет оператор `assert`, обеспечивая более четкую "
"обработку ошибок в случаях, когда конфигурация приложения неверна."

#: of vstutils.utils.raise_misconfiguration:7
msgid ""
"A value of any type that can be evaluated as a boolean. If the boolean "
"evaluation returns False, the exception will be raised."
msgstr ""
"Значение любого типа, которое может быть оценено как логическое. Если "
"логическая оценка возвращает False, будет вызвано исключение."

#: of vstutils.utils.raise_misconfiguration:13
msgid ""
"An optional message to include in the exception. If not provided, the "
"exception will be raised without a message."
msgstr ""
"Необязательное сообщение, которое будет включено в исключение. Если оно "
"не указано, исключение будет вызвано без сообщения."

#: of vstutils.utils.raise_misconfiguration:18
msgid ""
"Raised if the boolean evaluation of the `ok` parameter is False, "
"indicating a misconfiguration in the application."
msgstr ""
"Вызывается, если логическая оценка параметра `ok` равна False, что "
"указывает на ошибку конфигурации в приложении."

#: of vstutils.utils.raise_misconfiguration:22
msgid ""
"This function does not return any value. It either passes silently or "
"raises an exception."
msgstr ""
"Эта функция не возвращает никакого значения. Она либо выполняется без "
"ошибок, либо вызывает исключение."

#: of vstutils.utils.redirect_stdany:1
msgid "Context for redirect any output to own stream."
msgstr "Контекст для перенаправления любого вывода в свой поток."
Expand Down
1 change: 1 addition & 0 deletions requirements-rtd.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ django~=5.0.8
httpx>=0.27.0
typing-extensions
sphinx-intl~=2.2.0
orjson==3.9.13
14 changes: 10 additions & 4 deletions test_src/test_proj/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2127,7 +2127,10 @@ def has_deep_parent_filter(params):

# Check hide non required fields option
self.assertTrue(api['definitions']['SubVariables']['x-hide-not-required'])

# Check display mode settings
self.assertEqual(api['definitions']['SubVariables']['x-display-mode'], 'STEP')
self.assertEqual(api['definitions']['RowList']['x-display-mode-list'], 'TABLE')

# Check public centrifugo address when absolute path is provided
self.assertEqual(api['info']['x-centrifugo-address'], 'wss://vstutilstestserver/notify/connection/websocket')
Expand Down Expand Up @@ -4636,6 +4639,7 @@ def test_model_namedbinfile_field(self):
{'method': 'post', 'path': ['testbinaryfiles'], 'data': {'some_validatedmultiplenamedbinimage': [valid_image_content_dict]}},
{'method': 'get', 'path': ['testbinaryfiles', instance_without_mediaType.id, 'test_pydantic']},
{'method': 'get', 'path': ['testbinaryfiles', instance_without_mediaType.id, 'test_pydantic_list']},
{'method': 'get', 'path': ['testbinaryfiles', 'test_list']},
]
results = self.bulk(bulk_data)
self.assertEqual(results[0]['status'], 201)
Expand Down Expand Up @@ -4699,6 +4703,8 @@ def test_model_namedbinfile_field(self):
self.assertEqual(results[37]['data']['count'], 2)
self.assertEqual(results[37]['data']['results'], [{'id': 1}, {'id': 2}])

self.assertEqual(results[38]['data'], {"items": [{'id': 1}, {'id': 2}]})

def test_file_field(self):
with open(os.path.join(DIR_PATH, 'cat.jpeg'), 'rb') as cat1:
cat64 = base64.b64encode(cat1.read()).decode('utf-8')
Expand Down Expand Up @@ -6151,18 +6157,18 @@ def test_instantiation(self):
"Remove `source=` from the field declaration."
)

with self.assertRaises(AssertionError, msg=msg_to_check):
with self.assertRaises(ImproperlyConfigured, msg=msg_to_check):
vstfields.QrCodeField(child=fields.CharField(source='some_source'))

with self.assertRaises(AssertionError, msg=msg_to_check):
with self.assertRaises(ImproperlyConfigured, msg=msg_to_check):
vstfields.Barcode128Field(child=fields.CharField(source='some_source'))

msg_to_check = '`child` has not been instantiated.'

with self.assertRaises(AssertionError, msg=msg_to_check):
with self.assertRaises(ImproperlyConfigured, msg=msg_to_check):
vstfields.QrCodeField(child=fields.CharField)

with self.assertRaises(AssertionError, msg=msg_to_check):
with self.assertRaises(ImproperlyConfigured, msg=msg_to_check):
vstfields.Barcode128Field(child=fields.CharField)

def test_barcode128_validation(self):
Expand Down
17 changes: 16 additions & 1 deletion test_src/test_proj/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

import pydantic
from django.utils.functional import SimpleLazyObject
from rest_framework.fields import IntegerField
from rest_framework.permissions import AllowAny

from vstutils.api import responses, filter_backends, fields
from vstutils.api.views import SettingsViewSet
from vstutils.api.base import GenericViewSet, NonModelsViewSet
from vstutils.api.decorators import action, nested_view, subaction, extend_filterbackends
from vstutils.api.serializers import DataSerializer, JsonObjectSerializer, EmptySerializer
from vstutils.api.serializers import DataSerializer, JsonObjectSerializer, EmptySerializer, BaseSerializer, DisplayModeList
from vstutils.api.auth import UserViewSet
from vstutils.api.actions import Action, SimpleAction, SimpleFileAction
from vstutils.utils import create_view
Expand Down Expand Up @@ -144,7 +145,21 @@ class TestBinaryFilesPydantic(pydantic.BaseModel):
id: int


class RowListSerializer(BaseSerializer):
_display_mode_list = DisplayModeList.TABLE

id = IntegerField(read_only=True)


class PrettyTableSerializer(BaseSerializer):
items = RowListSerializer(many=True)


class TestBinaryFilesViewSet(ModelWithBinaryFiles.generated_view):
@SimpleAction(serializer_class=PrettyTableSerializer, detail=False)
def test_list(self, request, *args, **kwargs):
return {"items": self.get_queryset()}

@SimpleAction(serializer_class=TestBinaryFilesPydantic)
def test_pydantic(self, request, *args, **kwargs):
return self.get_object()
Expand Down
Loading

0 comments on commit 6081d02

Please sign in to comment.