Backend API manual

VST Utils framework uses Django, Django Rest Framework, drf-yasg and Celery.

Models

A model is the single, definitive source of truth about your data. It contains essential fields and behavior for the data you’re storing. Usually best practice is to avoid writing views and serializers manually, as BModel provides plenty of Meta attributes to autogenerate serializers and views for many use cases.

Default Django model classes overrides in vstutils.models module.

class vstutils.models.BModel(*args, **kwargs)[source]

Default model class that generates model viewset, separate serializers for list() and retrieve(), filters, api endpoints and nested views.

Examples:
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
            }
        }

In this case, you create models which could converted to simple view, where:

  • POST/GET to /api/version/task/ - creates new or get list of tasks

  • PUT/PATCH/GET/DELETE to /api/version/task/:id/ - updates, retrieves or removes instance of task

  • POST/GET to /api/version/task/:id/stage/ - creates new or get list of stages in task

  • PUT/PATCH/GET/DELETE to /api/version/task/:id/stage/:stage_id - updates, retrieves or removes instance of stage in task.

To attach a view to an API insert the following code in settings.py:

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

For primary access to generated view inherit from Task.generated_view property.

To make translation on frontend easier use _translate_model attribute with model_name.

List of meta-attributes for generating a view:

  • _view_class - list of additional view classes to inherit from, class or string to import with base class ViewSet. Constants are also supported:

    • read_only - to create a view only for viewing;

    • list_only - to create a view with list only;

    • history - to create a view only for viewing and deleting records.

    CRUD-view is applied by default.

  • _serializer_class - class of API serializer; use this attribute to specify parent class for autogenerated serializers. Default is vstutils.api.serializers.VSTSerializer. Can take a string to import, serializer class or django.utils.functional.SimpleLazyObject.

  • _serializer_class_name - model name for OpenAPI definitions.This would be a model name in generated admin interface. Default is name of model class.

  • _list_fields or _detail_fields - list of fields which will be listed in entity list or detail view accordingly. Same as DRF serializers meta-attribute “fields”.

  • _override_list_fields or _override_detail_fields - mapping with names and field types that will be redeclared in serializer attributes(think of it as declaring fields in DRF ModelSerializer).

  • _properties_groups - dict with key as group name and value as list of fields(str). Allows to group fields in sections on frontend.

  • _view_field_name - name of field frontend shows as main view name.

  • _non_bulk_methods - list of methods which must not used via bulk requests.

  • _extra_serializer_classes - mapping with additional serializers in viewset. For example, custom serializer, which will compute smth in action (mapping name). Value can be string for import. Important note: setting model attribute to None allows to use standard serializer generation mechanism and get fields from a list or detail serializer (set __inject_from__ serializer’s meta attribute to list or detail accordingly). In some cases, it is required to pass the model to the serializer. For these purposes, the constant LAZY_MODEL can be used as a meta attribute. Each time the serializer is used, the exact model where this serializer was declared will be set.

  • _filterset_fields - list/dict of filterset names for API-filtering. Default is list of fields in list view. During processing a list of fields checks for the presence of special field names and inherit additional parent classes. If the list contains id, class will inherit from vstutils.api.filters.DefaultIDFilter. If the list contains name, class will inherit from vstutils.api.filters.DefaultNameFilter. If both conditions are present, inheritance will be from all of the above classes. Possible values include list of fields to filter or dict where key is a field name and value is a Filter class. Dict extends attribute functionality and provides ability to override filter field class (None value disables overriding).

  • _search_fields - tuple or list of fields using for search requests. By default (or None) get all filterable fields in detail view.

  • _copy_attrs - list of model-instance attributes indicates that object is copyable with this attrs.

  • _nested - key-value mapping with nested views (key - nested name, kwargs for vstutils.api.decorators.nested_view decorator but supports model attribute as nested). model can be string for import. Use override_params when you need to override generated view parameters for nested view (works only with model as view).

  • _extra_view_attributes - key-value mapping with additional view attributes, but has less priority over generated attributes.

In common, you can also add custom attributes to override or extend the default list of processing classes. Supported view attributes are filter_backends, permission_classes, authentication_classes, throttle_classes, renderer_classes and parser_classes. List of meta-attributes for settings of view is looks like:

  • _pre_{attribute} - List of classes included before defaults.

  • _{attribute} - List of classes included after defaults.

  • _override_{attribute} - boolean flag indicates that attribute override default viewset (otherwise appends). Default is False.

Note

You may need to create an action on generated view. Use vstutils.models.decorators.register_view_action decorator with the detail argument to determine applicability to a list or detail entry. In this case, the decorated method will take an instance of the view object as self attribute.

Note

In some cases, inheriting models may require to inherit Meta class from the base model. If the Meta is explicitly declared in the base class, then you can get it through the attribute OriginalMeta and use it for inheritance.

Note

Docstring of model will be reused for view descriptions. It is possible to write both a general description for all actions and description for each action using the following syntax:

General description for all actions.

action_name:
    Description for this action.

another_action:
    Description for another action.

The get_view_class() method is a utility method in the Django ORM model designed to facilitate the configuration and instantiation of Django Rest Framework (DRF) Generic ViewSets. It allows developers to define and customize various aspects of the associated DRF view class.

Examples:
# 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)
            },
        },
    },
)

Developers can use this method to customize various aspects of the associated view, such as serializer classes, field configurations, filter backends, permission classes, etc. It uses attributes declared in meta attributes, but allows individual parts to be overriden.

hidden

If hidden is set to True, entry will be excluded from query in BQuerySet.

id

Primary field for select and search in API.

class vstutils.models.Manager(*args, **kwargs)[source]

Default VSTUtils manager. Used by BaseModel and BModel. Uses BQuerySet as base.

class vstutils.models.queryset.BQuerySet(model=None, query=None, using=None, hints=None)[source]

Represent a lazy database lookup for a set of objects. Allows to override default iterable class by custom_iterable_class attribute (class with __iter__ method which returns generator of model objects) and default query class by custom_query_class attribute (class inherited from django.db.models.sql.query.Query).

cleared()[source]

Filter queryset for models with attribute ‘hidden’ and exclude all hidden objects.

get_paginator(*args, **kwargs)[source]

Returns initialized object of vstutils.utils.Paginator over current instance’s QuerySet. All args and kwargs go to to Paginator’s constructor.

paged(*args, **kwargs)[source]

Returns paginated data with custom Paginator-class. Uses PAGE_LIMIT from global settings by default.

class vstutils.models.decorators.register_view_action(*args, **kwargs)[source]

Decorator for turning model methods to generated view actions. When a method is decorated, it becomes a part of the generated view and the self reference within the method points to the view object. This allows you to extend the functionality of generated views with custom actions.

The register_view_action decorator supports various arguments, and you can refer to the documentation for vstutils.api.decorators.subaction() to explore the complete list of supported arguments. These arguments provide flexibility in defining the behavior and characteristics of the generated view actions.

Note

In scenarios where you’re working with proxy models that share a common set of actions, you can use the inherit named argument with a value of True. This allows the proxy model to inherit actions defined in the base model, reducing redundancy and promoting code reuse.

Note

In many cases, an action may not require any parameters and can be executed by sending an empty query. To streamline development and enhance efficiency, the register_view_action decorator sets the default serializer to vstutils.api.serializers.EmptySerializer. This means that the action expects no input data, making it convenient for actions that operate without additional parameters.

Example:

This example demonstrates how to use the decorator to create a custom action within a model view. The empty_action method becomes part of the generated view and expects no input parameters.

from vstutils.models import BModel
from vstutils.models.decorators import register_view_action
from vstutils.api.responses import HTTP_200_OK


class MyModel(BModel):
    # ... model fields ...

    @register_view_action(detail=False, inherit=True)
    def empty_action(self, request, *args, **kwargs):
        # in this case `self` will be reference within the method points to the view object
        return HTTP_200_OK('OK')

Vstutils supports models that don’t necessitate direct database interaction or aren’t inherently tied to database tables. These models exhibit diverse behaviors, such as fetching data directly from class attributes, loading data from files, or implementing custom data retrieval mechanisms. Remarkably, there are models that, in a sense, implement the mechanism of SQL views with pre-defined queries. This flexibility allows developers to define a wide range of models that cater to specific data needs, from in-memory models to those seamlessly integrating external data sources. Vstutils’ model system is not confined to traditional database-backed structures, providing a versatile foundation for crafting various data representations.

class vstutils.models.custom_model.ExternalCustomModel(*args, **kwargs)[source]

Represents a custom model designed for the self-implementation of requests to external services.

This model facilitates the seamless interaction with external services by allowing the passing of filtering, limiting, and sorting parameters to an external request. It is designed to receive data that is already filtered and limited.

To utilize this model effectively, developers need to implement the get_data_generator() class method. This method receives a query object containing the necessary parameters, enabling developers to customize interactions with external services.

Example:

class MyExternalModel(ExternalCustomModel):
    # ... model fields ...

    class Meta:
        managed = False

    @classmethod
    def get_data_generator(cls, query):
        data = ... # some fetched data from the external resource or generated from memory calculations.
        for row in data:
            yield row
classmethod get_data_generator(query)[source]

This class method must be implemented by derived classes to define custom logic for fetching data from an external service based on the provided query parameters.

Query object might contain the following parameters:

  • filter (dict): A dictionary specifying the filtering criteria.

  • exclude (dict): A dictionary specifying the exclusion criteria.

  • order_by (list): A list specifying the sorting order.

  • low_mark (int): The low index for slicing (if sliced).

  • high_mark (int): The high index for slicing (if sliced).

  • is_sliced (bool): A boolean indicating whether the query is sliced.

Parameters:

query (dict) – An object containing filtering, limiting, and sorting parameters.

Returns:

A generator that yields the requested data.

Return type:

Generator

Raises:

NotImplementedError – If the method is not implemented by the derived class.

class vstutils.models.custom_model.FileModel(*args, **kwargs)[source]

Custom model that loads data from a YAML file instead of a database. The path to the file is specified in the FileModel.file_path attribute.

Examples:

Suppose the source file is stored at /etc/authors.yaml with the following content:

- name: "Sergey Klyuykov"
- name: "Michael Taran"

You can create a custom model using this file:

from vstutils.custom_model import FileModel, CharField

class Authors(FileModel):
    name = CharField(max_length=512)

    file_path = '/etc/authors.yaml'
class vstutils.models.custom_model.ListModel(*args, **kwargs)[source]

Custom model which uses a list of dicts with data (attribute ListModel.data) instead of database records. Useful when you have a simple list of data.

Examples:
from vstutils.custom_model import ListModel, CharField


class Authors(ListModel):
    name = CharField(max_length=512)

    data = [
        {"name": "Sergey Klyuykov"},
        {"name": "Michael Taran"},
    ]

Sometimes, it may be necessary to switch the data source. For these purposes, you should use the setup_custom_queryset_kwargs function, which takes various named arguments, which are also passed to the data initialization function. One such argument for ListModel is date_source, which takes any iterable object.

Examples:
from vstutils.custom_model import ListModel, CharField


class Authors(ListModel):
    name = CharField(max_length=512)

qs = Authors.objects.setup_custom_queryset_kwargs(data_source=[
    {"name": "Sergey Klyuykov"},
    {"name": "Michael Taran"},
])

In this case, we setup source list via setup_custom_queryset_kwargs function, and any other chained call is going to work with this data.

Variables:

data (list) – List with data dicts. Empty by default.

class vstutils.models.custom_model.ViewCustomModel(*args, **kwargs)[source]

Implements the SQL View programming mechanism over other models.

This model provides a mechanism for implementing SQL View-like behavior over other models. In the get_view_queryset() method, a base query is prepared, and all further actions are implemented on top of it.

Example Usage:

class MyViewModel(ViewCustomModel):
    # ... model fields ...

    class Meta:
        managed = False

    @classmethod
    def get_view_queryset(cls):
        return SomeModel.objects.annotate(...)  # add some additional annotations to query
classmethod get_view_queryset()[source]

This class method must be implemented by derived classes to define custom logic for generating the base queryset for the SQL View.

Returns:

The base queryset for the SQL View.

Return type:

django.db.models.query.QuerySet

Raises:

NotImplementedError – If the method is not implemented by the derived class.

Model Fields

class vstutils.models.fields.FkModelField(to, on_delete, related_name=None, related_query_name=None, limit_choices_to=None, parent_link=False, to_field=None, db_constraint=True, **kwargs)[source]

Extends django.db.models.ForeignKey. Use this field in vstutils.models.BModel to get vstutils.api.FkModelField in serializer. To set Foreign Key relation set to argument to string path to model or to Model Class as in django.db.models.ForeignKey

class vstutils.models.fields.HTMLField(*args, db_collation=None, **kwargs)[source]

Extends django.db.models.TextField. A simple field for storing HTML markup. The field is based on django.db.models.TextField, therefore it does not support indexing and is not recommended for use in filters.

class vstutils.models.fields.MultipleFieldFile(instance, field, name)[source]

Subclasses django.db.models.fields.files.FieldFile. Provides MultipleFieldFile.save() and MultipleFieldFile.delete() to manipulate the underlying file, as well as update the associated model instance.

delete(save=True)[source]

Delete file from storage and from object attr.

save(name, content, save=True)[source]

Save changes in file to storage and to object attr.

class vstutils.models.fields.MultipleFileDescriptor(field)[source]

Subclasses django.db.models.fields.files.FileDescriptor to handle list of files. Return a list of MultipleFieldFile when accessed so you can write code like:

from myapp.models import MyModel
instance = MyModel.objects.get(pk=1)
instance.files[0].size
get_file(file, instance)[source]

Always return valid attr_class object. For details on logic see django.db.models.fields.files.FileDescriptor.__get__().

class vstutils.models.fields.MultipleFileField(**kwargs)[source]

Subclasses django.db.models.fields.files.FileField. Field for storing a list of Storage-kept files. All args passed to FileField.

attr_class

alias of MultipleFieldFile

descriptor_class

alias of MultipleFileDescriptor

class vstutils.models.fields.MultipleFileMixin(**kwargs)[source]

Mixin suited to use with django.db.models.fields.files.FieldFile to transform it to a Field with list of files.

get_prep_value(value)[source]

Prepare value for database insertion

pre_save(model_instance, add)[source]

Call .save() method on every file in list

class vstutils.models.fields.MultipleImageField(**kwargs)[source]

Field for storing a list of storage-kept images. All args are passed to django.db.models.fields.files.ImageField, except height_field and width_field, they are not currently implemented.

attr_class

alias of MultipleImageFieldFile

descriptor_class

alias of MultipleFileDescriptor

class vstutils.models.fields.MultipleImageFieldFile(instance, field, name)[source]

Subclasses MultipleFieldFile and ImageFile mixin, handles deleting _dimensions_cache when file is deleted.

class vstutils.models.fields.MultipleNamedBinaryFileInJSONField(*args, db_collation=None, **kwargs)[source]

Extends django.db.models.TextField. Use this field in vstutils.models.BModel to get vstutils.api.MultipleNamedBinaryFileInJSONField in serializer.

class vstutils.models.fields.MultipleNamedBinaryImageInJSONField(*args, db_collation=None, **kwargs)[source]

Extends django.db.models.TextField. Use this field in vstutils.models.BModel to get vstutils.api.MultipleNamedBinaryImageInJSONField in serializer.

class vstutils.models.fields.NamedBinaryFileInJSONField(*args, db_collation=None, **kwargs)[source]

Extends django.db.models.TextField. Use this field in vstutils.models.BModel to get vstutils.api.NamedBinaryFileInJSONField in serializer.

class vstutils.models.fields.NamedBinaryImageInJSONField(*args, db_collation=None, **kwargs)[source]

Extends django.db.models.TextField. Use this field in vstutils.models.BModel to get vstutils.api.NamedBinaryImageInJSONField in serializer.

class vstutils.models.fields.WYSIWYGField(*args, db_collation=None, **kwargs)[source]

Extends django.db.models.TextField. A simple field for storing Markdown data. The field is based on django.db.models.TextField, therefore it does not support indexing and is not recommended for use in filters.

Web API

Web API is based on Django Rest Framework with additional nested functions.

Fields

The Framework includes a list of convenient serializer fields. Some of them take effect only in generated admin interface.

Additional serializer fields for generating OpenAPI and GUI.

class vstutils.api.fields.AutoCompletionField(*args, **kwargs)[source]

Serializer field that provides autocompletion on the frontend, using a specified list of objects.

Parameters:
  • autocomplete (list, tuple, str) – Autocompletion reference. You can set a list or tuple with values or specify the name of an OpenAPI schema definition. For a definition name, the GUI will find the optimal link and display values based on the autocomplete_property and autocomplete_represent arguments.

  • autocomplete_property (str) – Specifies which attribute to retrieve from the OpenAPI schema definition model as the value. Default is ‘id’.

  • autocomplete_represent – Specifies which attribute to retrieve from the OpenAPI schema definition model as the representational value. Default is ‘name’.

  • use_prefetch (bool) – Prefetch values on the frontend in list view. Default is True.

Note

This functionality is effective only in the GUI. In the API, it behaves similarly to VSTCharField.

Usage:

This field is designed to be used in serializers where a user needs to input a value, and autocompletion based on a predefined list or an OpenAPI schema definition is desired. If an OpenAPI schema is specified, two additional parameters, autocomplete_property and autocomplete_represent, can be configured to customize the appearance of the dropdown list.

Example:

from vstutils.api import serializers
from vstutils.api.fields import AutoCompletionField


class MyModelSerializer(serializers.BaseSerializer):
    name = AutoCompletionField(autocomplete=['Option 1', 'Option 2', 'Option 3'])

# or

class MyModelSerializer(serializers.BaseSerializer):
    name = AutoCompletionField(
        autocomplete='MyModelSchema',
        autocomplete_property='custom_property',
        autocomplete_represent='display_name'
    )
class vstutils.api.fields.Barcode128Field(*args, **kwargs)[source]

A field for representing data as a Barcode (Code 128) in the user interface.

This field accepts and validates data in the form of a valid ASCII string. It is designed to display the data as a Code 128 barcode in the graphical user interface. The underlying data is serialized or deserialized using the specified child field.

Parameters:

child (rest_framework.fields.Field) – The original data field for serialization or deserialization. Default: rest_framework.fields.CharField

Example:

Suppose you have a model with a product_code field, and you want to display its Code 128 barcode representation in the GUI. You can use Barcode128Field in your serializer:

class Product(BModel):
    product_code = models.CharField(max_length=20)

class ProductSerializer(VSTSerializer):
    barcode = Barcode128Field(child=serializers.CharField(source='product_code'))

    class Meta:
        model = Product
        fields = '__all__'
class vstutils.api.fields.BinFileInStringField(*args, **kwargs)[source]

This field extends FileInStringField and is specifically designed to handle binary files. In the GUI, it functions as a file input field, accepting binary files from the user, which are then converted to base64-encoded strings and stored in this field.

Parameters:

media_types (tuple, list) – A list of MIME types to filter on the user’s side. Supports the use of * as a wildcard. Default: [‘*/*’]

Note

This functionality is effective only in the GUI. In the API, it behaves similarly to VSTCharField.

class vstutils.api.fields.CSVFileField(*args, **kwargs)[source]

Field extends FileInStringField, using for works with csv files. This field provides the display of the loaded data in the form of a table.

Parameters:
  • items (Serializer) –

    The config of the table. This is a drf or vst serializer which includes char fields which are the keys in the dictionaries into which the data from csv is serialized and the names for columns in a table. The fields must be in the order you want them to appear in the table. Following options may be included:

    • label: human readable column name

    • required: Defines whether the field should be required. False by default.

  • min_column_width (int) – Minimum cell width. Default is 200 px.

  • delimiter (str) – The delimiting character.

  • lineterminator (str) – The newline sequence. Leave blank to auto-detect. Must be one of \r, \n, or \r\n.

  • quotechar (str) – The character used to quote fields.

  • escapechar (str) – The character used to escape the quote character within a field.

  • media_types (tuple,list) – List of MIME types to select on the user’s side. Supported syntax using *. Default: ['text/csv']

class vstutils.api.fields.CommaMultiSelect(*args, **kwargs)[source]

Field that allows users to input multiple values, separated by a specified delimiter (default: “,”). It retrieves a list of values from another model or a custom list and provides autocompletion similar to AutoCompletionField. This field is suitable for property fields in a model where the main logic is already implemented or for use with model.CharField.

Parameters:
  • select (str, tuple, list) – OpenAPI schema definition name or a list with values.

  • select_separator (str) – The separator for values. The default is a comma.

  • select_represent (select_property,) – These parameters function similarly to autocomplete_property and autocomplete_represent. The default is name.

  • use_prefetch (bool) – Prefetch values on the frontend in list view. The default is False.

  • make_link (bool) – Show values as links to the model. The default is True.

  • dependence (dict) – A dictionary where keys are the names of fields from the same model, and values are the names of query filters. If at least one of the fields we depend on is non-nullable, required, and set to null, the autocompletion list will be empty, and the field will be disabled.

Example:

from vstutils.api import serializers
from vstutils.api.fields import CommaMultiSelect

class MyModelSerializer(serializers.BaseSerializer):
    tags = CommaMultiSelect(
        select="TagsReferenceSchema",
        select_property='slug',
        select_represent='slug',
        use_prefetch=True,
        make_link=False,
        dependence={'some_field': 'value'},
    )

# or

class MyModelSerializer(serializers.BaseSerializer):
    tags = CommaMultiSelect(select=['tag1', 'tag2', 'tag3'])

Note

This functionality is effective only in the GUI and works similarly to VSTCharField in the API.

class vstutils.api.fields.CrontabField(*args, **kwargs)[source]

Simple crontab-like field which contains the schedule of cron entries to specify time. A crontab field has five fields for specifying day, date and time. * in the value field above means all legal values as in braces for that column.

The value column can have a * or a list of elements separated by commas. An element is either a number in the ranges shown above or two numbers in the range separated by a hyphen (meaning an inclusive range).

The time and date fields are:

field

allowed value

minute

0-59

hour

0-23

day of month

1-31

month

1-12

day of week

0-7 (0 or 7 is Sunday)

Default value of each field if not specified is *.

.---------------- minute (0 - 59)
| .-------------- hour (0 - 23)
| | .------------ day of month (1 - 31)
| | | .---------- month (1 - 12)
| | | | .-------- day of week (0 - 6) (Sunday=0 or 7)
| | | | |
* * * * *
class vstutils.api.fields.DeepFkField(only_last_child=False, parent_field_name='parent', **kwargs)[source]

Extends FkModelField, specifically designed for hierarchical relationships in the frontend.

This field is intended for handling ForeignKey relationships within a hierarchical or tree-like structure. It displays as a tree in the frontend, offering a clear visual representation of parent-child relationships.

Warning

This field intentionally does not support the dependence parameter, as it operates in a tree structure. Usage of filters should be approached with caution, as inappropriate filters may disrupt the tree hierarchy.

Parameters:
  • only_last_child (bool) – If True, the field restricts the selection to nodes without children. Default is False. Useful when you want to enforce selection of leaf nodes.

  • parent_field_name (str) – The name of the parent field in the related model. Default is parent. Should be set to the ForeignKey field in the related model, representing the parent-child relationship. For example, if your related model has a ForeignKey like parent = models.ForeignKey(‘self’, …), then parent_field_name should be set to ‘parent’.

Examples:

Consider a related model with a ForeignKey field representing parent-child relationships:

class Category(BModel):
    name = models.CharField(max_length=255)
    parent = models.ForeignKey('self', null=True, default=None, on_delete=models.CASCADE)

To use the DeepFkField with this related model in a serializer, you would set the parent_field_name to ‘parent’:

class MySerializer(VSTSerializer):
    category = DeepFkField(select=Category, parent_field_name='parent')

This example assumes a Category related model with a ForeignKey ‘parent’ field. The DeepFkField will then display the categories as a tree structure in the frontend, providing an intuitive selection mechanism for hierarchical relationships.

Note

Effective only in GUI. Works similarly to rest_framework.fields.IntegerField in API.

class vstutils.api.fields.DependEnumField(*args, **kwargs)[source]

Field extends DynamicJsonTypeField but its value is not transformed to json and would be given as is. Useful for property in models or for actions.

Parameters:
  • field (str) – field in model which value change will change type of current value.

  • types – key-value mapping where key is value of subscribed field and value is type (in OpenAPI format) of current field.

  • choices (dict) – variants of choices for different subscribed field values. Uses mapping where key is value of subscribed field and value is list with values to choice.

Note

Effective only in GUI. In API works similar to VSTCharField without value modification.

class vstutils.api.fields.DependFromFkField(*args, **kwargs)[source]

A specialized field that extends DynamicJsonTypeField and validates field data based on a field_attribute chosen in a related model. The field data is validated against the type defined by the chosen value of field_attribute.

Note

By default, any value of field_attribute validates as VSTCharField. To override this behavior, set the class attribute {field_attribute}_fields_mapping in the related model. The attribute should be a dictionary where keys are string representations of the values of field_attribute, and values are instances of rest_framework.Field for validation. If a value is not found in the dictionary, the default type will be VSTCharField.

Parameters:
  • field (str) – The field in the model whose value change determines the type of the current value. The field must be of type FkModelField.

  • field_attribute (str) – The attribute of the related model instance containing the name of the type.

  • types (dict) – A key-value mapping where the key is the value of the subscribed field, and the value is the type (in OpenAPI format) of the current field.

Warning

The field_attribute in the related model must be of type rest_framework.fields.ChoicesField to ensure proper functioning in the GUI; otherwise, the field will be displayed as simple text.

Example:

Suppose you have a model with a ForeignKey field related_model and a field type_attribute in RelatedModel that determines the type of data. You can use DependFromFkField to dynamically adapt the serialization based on the value of type_attribute:

class RelatedModel(BModel):
    # ... other fields ...
    type_attribute = models.CharField(max_length=20, choices=[('type1', 'Type 1'), ('type2', 'Type 2')])

    type_attribute_fields_mapping = {
        'type1': SomeSerializer(),
        'type2': IntegerField(max_value=1337),
    }

class MyModel(BModel):
    related_model = models.ForeignKey(RelatedModel, on_delete=models.CASCADE)

class MySerializer(VSTSerializer):
    dynamic_field = DependFromFkField(
        field='related_model',
        field_attribute='type_attribute'
    )

    class Meta:
        model = MyModel
        fields = '__all__'
class vstutils.api.fields.DynamicJsonTypeField(*args, **kwargs)[source]

A versatile serializer field that dynamically adapts its type based on the value of another field in the model. It facilitates complex scenarios where the type of data to be serialized depends on the value of a related field.

Parameters:
  • field (str) – The field in the model whose value change will dynamically determine the type of the current field.

  • types (dict) – A key-value mapping where the key is the value of the subscribed field, and the value is the type (in OpenAPI format) of the current field.

  • choices (dict) – Variants of choices for different subscribed field values. Uses a mapping where the key is the value of the subscribed field, and the value is a list with values to choose from.

  • source_view (str) – Allows using parent views data as a source for field creation. The exact view path (/user/{id}/) or relative parent specifier (<<parent>>.<<parent>>.<<parent>>) can be provided. For example, if the current page is /user/1/role/2/ and source_view is <<parent>>.<<parent>>, then data from /user/1/ will be used. Only detail views are supported.

Example:

Suppose you have a serializer MySerializer with a field_type (e.g., a ChoiceField) and a corresponding object_data. The object_data field can have different types based on the value of field_type. Here’s an example configuration:

class MySerializer(VSTSerializer):
    field_type = serializers.ChoiceField(choices=['serializer', 'integer', 'boolean'])
    object_data = DynamicJsonTypeField(
        field='field_type',
        types={
            'serializer': SomeSerializer(),
            'integer': IntegerField(max_value=1337),
            'boolean': 'boolean',
        },
    )

In this example, the object_data field dynamically adapts its type based on the selected value of field_type. The types argument defines different types for each possible value of field_type, allowing for flexible and dynamic serialization.

class vstutils.api.fields.FileInStringField(*args, **kwargs)[source]

This field extends VSTCharField and stores the content of a file as a string.

The value must be text (not binary) and is saved in the model as is.

Parameters:

media_types (tuple, list) – A list of MIME types to filter on the user’s side. Supports the use of * as a wildcard. Default: ['*/*']

Note

This setting only takes effect in the GUI. In the API, it behaves like VSTCharField.

class vstutils.api.fields.FkField(*args, **kwargs)[source]

An implementation of ForeignKeyField, designed for use in serializers. This field allows you to specify which field of a related model will be stored in the field (default: “id”), and which field will represent the value on the frontend.

Parameters:
  • select (str) – OpenAPI schema definition name.

  • autocomplete_property (str) – Specifies which attribute will be retrieved from the OpenAPI schema definition model as the value. Default is id.

  • autocomplete_represent – Specifies which attribute will be retrieved from the OpenAPI schema definition model as the representational value. Default is name.

  • field_type (type) – Defines the type of the autocomplete_property for further definition in the schema and casting to the type from the API. Default is passthrough but requires int or str objects.

  • use_prefetch (bool) – Prefetch values on the frontend at list-view. Default is True.

  • make_link (bool) – Show the value as a link to the related model. Default is True.

  • dependence (dict) –

    A dictionary where keys are names of fields from the same model, and values are names of query filters. If at least one of the fields that we depend on is non-nullable, required, and set to null, the autocompletion list will be empty, and the field will be disabled.

    There are some special keys for the dependence dictionary to get data that is stored on the frontend without additional database query:

    • '<<pk>>' gets the primary key of the current instance,

    • '<<view_name>>' gets the view name from the Vue component,

    • '<<parent_view_name>>' gets the parent view name from the Vue component,

    • '<<view_level>>' gets the view level,

    • '<<operation_id>>' gets the operation_id,

    • '<<parent_operation_id'>> gets the parent_operation_id.

Examples:
field = FkField(select=Category, dependence={'<<pk>>': 'my_filter'})

This filter will get the primary key of the current object and make a query on the frontend /category?my_filter=3 where 3 is the primary key of the current instance.

Parameters:

filters (dict) – A dictionary where keys are names of fields from a related model (specified by this FkField), and values are values of that field.

Note

The intersection of dependence.values() and filters.keys() will throw an error to prevent ambiguous filtering.

Note

Effective only in the GUI. Works similarly to rest_framework.fields.IntegerField in the API.

class vstutils.api.fields.FkModelField(*args, **kwargs)[source]

Extends FkField, but stores referred model class. This field is useful for django.db.models.ForeignKey fields in model to set.

Parameters:
  • select (vstutils.models.BModel,vstutils.api.serializers.VSTSerializer) – model class (based on vstutils.models.BModel) or serializer class which used in API and has path in OpenAPI schema.

  • autocomplete_property (str) – this argument indicates which attribute will be get from OpenAPI schema definition model as value. Default is id.

  • autocomplete_represent – this argument indicates which attribute will be get from OpenAPI schema definition model as represent value. Default is name.

  • use_prefetch – prefetch values on frontend at list-view. Default is True.

  • make_link – Show value as link to model. Default is True.

Warning

Model class get object from database during .to_internal_value execution. Be careful on mass save executions.

Warning

Permissions to model which is referred by this field, are not to be checked. You should check it manually in signals or validators.

class vstutils.api.fields.HtmlField(*args, **kwargs)[source]

A specialized field for handling HTML text content, marked with the format:html.

Note

This field is designed for use in the graphical user interface (GUI) and functions similarly to VSTCharField in the API.

Example:

If you have a model with an html_content field that stores HTML-formatted text, you can use HtmlField in your serializer to handle this content in the GUI:

class MyModel(BModel):
    html_content = models.TextField()

class MySerializer(VSTSerializer):
    formatted_html_content = HtmlField(source='html_content')

    class Meta:
        model = MyModel
        fields = '__all__'
class vstutils.api.fields.MaskedField(*args, **kwargs)[source]

Extends the ‘rest_framework.serializers.CharField’ class. Field that applies a mask to the input value.

This field is designed for applying a mask to the input value on the frontend. It extends the ‘rest_framework.serializers.CharField’ and allows the use of the IMask library for defining masks.

Parameters:

mask (dict, str) – The mask to be applied to the value. It can be either a dictionary or a string following the IMask library format.

Example:

In a serializer, include this field to apply a mask to a value:

class MySerializer(serializers.Serializer):
    masked_value = MaskedField(mask='000-000')

This example assumes a serializer where the masked_value field represents a value with a predefined mask. The MaskedField will apply the specified mask on the frontend, providing a masked input for users.

Note

The effectiveness of this field is limited to the frontend, and the mask is applied during user input.

class vstutils.api.fields.MultipleNamedBinaryFileInJsonField(*args, **kwargs)[source]

Extends NamedBinaryFileInJsonField but uses list of JSONs. Allows to operate with multiple files as list of NamedBinaryFileInJsonField.

Attrs: NamedBinaryInJsonField.file: if True, accept only subclasses of File as input. If False, accept only string input. Default: False.

file_field

alias of MultipleFieldFile

class vstutils.api.fields.MultipleNamedBinaryImageInJsonField(*args, **kwargs)[source]

Extends MultipleNamedBinaryFileInJsonField but uses list of JSONs. Used for operating with multiple images and works as list of NamedBinaryImageInJsonField.

Parameters:

background_fill_color (str) – Color to fill area that is not covered by image after cropping. Transparent by default but will be black if image format is not supporting transparency. Can be any valid CSS color.

class vstutils.api.fields.NamedBinaryFileInJsonField(*args, **kwargs)[source]

Field that represents a binary file in JSON format.

Parameters:
  • file (bool) – If True, accept only subclasses of File as input. If False, accept only string input. Default: False.

  • post_handlers (tuple,list) – Functions to process the file after validation. Each function takes two arguments: binary_data (file bytes) and original_data (reference to the original JSON object). The function should return the processed binary_data.

  • pre_handlers (tuple,list) – Functions to process the file before validation. Each function takes two arguments: binary_data (file bytes) and original_data (reference to the original JSON object). The function should return the processed binary_data.

  • max_content_size (int) – Maximum allowed size of the file content in bytes.

  • min_content_size (int) – Minimum allowed size of the file content in bytes.

  • min_length (int) – Minimum length of the file name. Only applicable when file=True.

  • max_length (int) – Maximum length of the file name. Only applicable when file=True.

This field is designed for storing binary files alongside their names in django.db.models.CharField or django.db.models.TextField model fields. All manipulations involving decoding and encoding binary content data occur on the client, imposing reasonable limits on file size.

Additionally, this field can construct a django.core.files.uploadedfile.SimpleUploadedFile from incoming JSON and store it as a file in django.db.models.FileField if the file attribute is set to True.

Example:

In a serializer, include this field to handle binary files:

class MySerializer(serializers.ModelSerializer):
    binary_data = NamedBinaryFileInJsonField(file=True)

This example assumes a serializer where the binary_data field represents binary file information in JSON format. The NamedBinaryFileInJsonField will then handle the storage and retrieval of binary files in a user-friendly manner.

The binary file is represented in JSON with the following properties:

  • name (str): Name of the file.

  • mediaType (str): MIME type of the file.

  • content (str or File): Content of the file. If file is True, it will be a reference to the file; otherwise, it will be base64-encoded content.

Warning

The client application will display the content as a download link. Users will interact with the binary file through the application, with the exchange between the Rest API and the client occurring through the presented JSON object.

class vstutils.api.fields.NamedBinaryImageInJsonField(*args, **kwargs)[source]

Field that represents an image in JSON format, extending NamedBinaryFileInJsonField.

Parameters:

background_fill_color (str) – Color to fill the area not covered by the image after cropping. Transparent by default but will be black if the image format does not support transparency. Can be any valid CSS color.

This field is designed for handling image files alongside their names in django.db.models.CharField or django.db.models.TextField model fields. It extends the capabilities of NamedBinaryFileInJsonField to specifically handle images.

Additionally, this field validates the image using the following validators: - vstutils.api.validators.ImageValidator - vstutils.api.validators.ImageResolutionValidator - vstutils.api.validators.ImageHeightValidator

When saving and with the added validators, the field will display a corresponding window for adjusting the image to the specified parameters, providing a user-friendly interface for managing images.

The image file is represented in JSON with the following properties:

  • name (str): Name of the image file.

  • mediaType (str): MIME type of the image file.

  • content (str or File): Content of the image file. If file is True, it will be a reference to the image file; otherwise, it will be base64-encoded content.

Warning

The client application will display the content as an image. Users will interact with the image through the application, with the exchange between the Rest API and the client occurring through the presented JSON object.

class vstutils.api.fields.PasswordField(*args, **kwargs)[source]

Extends CharField but in schema set format to password. Show all characters as asterisks instead of real value in GUI.

class vstutils.api.fields.PhoneField(*args, **kwargs)[source]

Extends the ‘rest_framework.serializers.CharField’ class. Field for representing a phone number in international format.

This field is designed for capturing and validating phone numbers in international format. It extends the ‘rest_framework.serializers.CharField’ and adds custom validation to ensure that the phone number contains only digits.

Example:

In a serializer, include this field to handle phone numbers:

class MySerializer(VSTSerializer):
    phone_number = PhoneField()

This example assumes a serializer where the phone_number field represents a phone number in international format. The PhoneField will then handle the validation and representation of phone numbers, making it convenient for users to input standardized phone numbers.

The field will be displayed in the client application as an input field for entering a phone number, including the country code.

class vstutils.api.fields.QrCodeField(*args, **kwargs)[source]

A versatile field for encoding various types of data into QR codes.

This field can encode a wide range of data into a QR code representation, making it useful for displaying QR codes in the user interface. It works by serializing or deserializing data using the specified child field.

Parameters:

child (rest_framework.fields.Field) – The original data field for serialization or deserialization. Default: rest_framework.fields.CharField

Example:

Suppose you have a model with a data field, and you want to display its QR code representation in the GUI. You can use QrCodeField in your serializer:

class MyModel(BModel):
    data = models.CharField(max_length=255)

class MySerializer(VSTSerializer):
    qr_code_data = QrCodeField(child=serializers.CharField(source='data'))

    class Meta:
        model = MyModel
        fields = '__all__'

In this example, the qr_code_data field will represent the QR code generated from the data field in the GUI. Users can interact with this QR code, and if their device supports it, they can scan the code for further actions.

class vstutils.api.fields.RatingField(min_value=0, max_value=5, step=1, front_style='stars', **kwargs)[source]

Extends class ‘rest_framework.serializers.FloatField’. This field represents a rating form input on frontend. Grading limits can be specified with ‘min_value=’ and ‘max_value=’, defaults are 0 to 5. Minimal step between grades are specified in ‘step=’, default - 1. Frontend visual representation can be chosen with ‘front_style=’, available variants are listed in ‘self.valid_front_styles’.

For ‘slider’ front style, you can specify slider color, by passing valid color to ‘color=’. For ‘fa_icon’ front style, you can specify FontAwesome icon that would be used for displaying rating, by passing a valid FontAwesome icon code to ‘fa_class=’.

Parameters:
  • min_value (float, int) – minimal level

  • max_value (float, int) – maximal level

  • step (float, int) – minimal step between levels

  • front_style (str) – visualization on frontend field. Allowed: [‘stars’, ‘slider’, ‘fa_icon’].

  • color (str) – color of rating element (star, icon or slider) in css format

  • fa_class (str) – FontAwesome icon code

class vstutils.api.fields.RedirectCharField(*args, **kwargs)[source]

Field for redirect by string. Often used in actions for redirect after execution.

Note

Effective only in GUI. Works similar to rest_framework.fields.IntegerField in API.

class vstutils.api.fields.RedirectFieldMixin(**kwargs)[source]

Field mixin indicates that this field is used to send redirect address to frontend after some action.

Parameters:
  • operation_name (str) – prefix for operation_id, for example if operation_id is history_get then operation_name is history

  • depend_field (str) – name of the field that we depend on, its value will be used for operation_id

  • concat_field_name (bool) – if True then name of the field will be added at the end of operation_id

class vstutils.api.fields.RedirectIntegerField(*args, **kwargs)[source]

Field for redirect by id. Often used in actions for redirect after execution.

Note

Effective only in GUI. Works similar to rest_framework.fields.IntegerField in API.

class vstutils.api.fields.RelatedListField(related_name, fields, view_type='list', serializer_class=None, **kwargs)[source]

Extends VSTCharField to represent a reverse ForeignKey relation as a list of related instances.

This field allows you to output the reverse ForeignKey relation as a list of related instances. To use it, specify the related_name kwarg (related manager for reverse ForeignKey) and the fields kwarg (list or tuple of fields from the related model to be included).

By default, VSTCharField is used to serialize all field values and represent them on the frontend. You can specify the serializer_class and override fields as needed. For example, title, description, and other field properties can be set to customize frontend behavior.

Parameters:
  • related_name (str) – Name of a related manager for reverse ForeignKey.

  • fields (list[str], tuple[str]) – List of related model fields.

  • view_type (str) – Determines how fields are represented on the frontend. Must be either list or table.

  • fields_custom_handlers_mapping (dict) – Custom handlers mapping, where key: field_name, value: callable_obj that takes params: instance[dict], fields_mapping[dict], model, field_name[str].

  • serializer_class (type) – Serializer to customize types of fields. If no serializer is provided, VSTCharField will be used for every field in the fields list.

class vstutils.api.fields.SecretFileInString(*args, **kwargs)[source]

This field extends FileInStringField but hides its value in the admin interface.

The value must be text (not binary) and is saved in the model as is.

Parameters:

media_types (tuple, list) – A list of MIME types to filter on the user’s side. Supports the use of * as a wildcard. Default: ['*/*']

Note

This setting only takes effect in the GUI. In the API, it behaves like VSTCharField.

class vstutils.api.fields.TextareaField(*args, **kwargs)[source]

A specialized field that allows the input and display of multiline text.

Note

This field is designed for use in the graphical user interface (GUI) and functions similarly to VSTCharField in the API.

Example:

Suppose you have a model with a description field that can contain multiline text. You can use TextareaField in your serializer to enable users to input and view multiline text in the GUI:

class MyModel(BModel):
    description = models.TextField()

class MySerializer(VSTSerializer):
    multiline_description = TextareaField(source='description')

    class Meta:
        model = MyModel
        fields = '__all__'
class vstutils.api.fields.UptimeField(*args, **kwargs)[source]

Time duration field, in seconds, specifically designed for computing and displaying system uptime.

This field is effective only in the GUI and behaves similarly to rest_framework.fields.IntegerField in the API.

The UptimeField class transforms time in seconds into a user-friendly representation on the frontend. It intelligently selects the most appropriate pattern from the following templates:

  • HH:mm:ss (e.g., 23:59:59)

  • dd HH:mm:ss (e.g., 01d 00:00:00)

  • mm dd HH:mm:ss (e.g., 01m 30d 00:00:00)

  • yy mm dd HH:mm:ss (e.g., 99y 11m 30d 22:23:24)

Example:

class MySerializer(serializers.ModelSerializer):
    uptime = UptimeField()

This example assumes a serializer where the uptime field represents a time duration in seconds. The UptimeField will then display the duration in a human-readable format on the frontend, making it convenient for users to interpret and input values.

Note

Effective only in GUI. Works similarly to rest_framework.fields.IntegerField in API.

class vstutils.api.fields.VSTCharField(*args, **kwargs)[source]

CharField (extends rest_framework.fields.CharField). This field translate any json type to string for model.

class vstutils.api.fields.WYSIWYGField(*args, **kwargs)[source]

Extends the TextareaField class to render the https://ui.toast.com/tui-editor on the frontend.

This field is specifically designed for rendering a WYSIWYG editor on the frontend, using the https://ui.toast.com/tui-editor. It saves data as markdown and escapes all HTML tags.

Parameters:

escape (bool) – HTML-escape input. Enabled by default to prevent HTML injection vulnerabilities.

Example:

In a serializer, include this field to render a WYSIWYG editor on the frontend:

class MySerializer(serializers.Serializer):
    wysiwyg_content = WYSIWYGField()

This example assumes a serializer where the wysiwyg_content field represents data to be rendered in a WYSIWYG editor on the frontend. The WYSIWYGField ensures that the content is saved as markdown and HTML tags are escaped to enhance security.

Warning

Enabling the escape option is recommended to prevent potential HTML injection vulnerabilities.

Note

The rendering on the frontend is achieved using the https://ui.toast.com/tui-editor.

Validators

There are validation classes for fields.

class vstutils.api.validators.FileMediaTypeValidator(extensions=None, **kwargs)[source]

Base Image Validation class. Validates media types.

Parameters:

extensions (typing.Union[typing.Tuple, typing.List, None]) – Tuple or List of file extensions, that should pass the validation

Raises rest_framework.exceptions.ValidationError: in case file extension are not in the list

class vstutils.api.validators.ImageBaseSizeValidator(extensions=None, **kwargs)[source]

Validates image size. To use this class for validating image width/height, rewrite self.orientation to (‘height’,) or (‘width’,) or (‘height’, ‘width’)

Raises rest_framework.exceptions.ValidationError: if not(min <= (height or width) <= max)

Parameters:

extensions (typing.Union[typing.Tuple, typing.List, None]) –

class vstutils.api.validators.ImageHeightValidator(extensions=None, **kwargs)[source]

Wrapper for ImageBaseSizeValidator that validates only height

Parameters:
class vstutils.api.validators.ImageOpenValidator(extensions=None, **kwargs)[source]

Image validator that checks if image can be unpacked from b64 to PIL Image obj. Won’t work if Pillow isn’t installed.

Raises rest_framework.exceptions.ValidationError if PIL throws error when trying to open image

Parameters:

extensions (typing.Union[typing.Tuple, typing.List, None]) –

class vstutils.api.validators.ImageResolutionValidator(extensions=None, **kwargs)[source]

Wrapper for ImageBaseSizeValidator that validates both height and width

Parameters:
  • min_height – minimal height of an image being validated

  • max_height – maximal height of an image being validated

  • min_width – minimal width of an image being validated

  • max_width – maximal width of an image being validated

  • extensions (typing.Union[typing.Tuple, typing.List, None]) –

class vstutils.api.validators.ImageValidator(extensions=None, **kwargs)[source]

Base Image Validation class. Validates image format. Won’t work if Pillow isn’t installed. Base Image Validation class. Validates media types.

Parameters:

extensions (typing.Union[typing.Tuple, typing.List, None]) – Tuple or List of file extensions, that should pass the validation

Raises rest_framework.exceptions.ValidationError: in case file extension are not in the list

property has_pillow

Check if Pillow is installed

class vstutils.api.validators.ImageWidthValidator(extensions=None, **kwargs)[source]

Wrapper for ImageBaseSizeValidator that validates only width

Parameters:
class vstutils.api.validators.RegularExpressionValidator(regexp=None)[source]

Class for regular expression based validation

Raises:

rest_framework.exceptions.ValidationError – in case value does not match regular expression

Parameters:

regexp (typing.Optional[typing.Pattern]) –

class vstutils.api.validators.UrlQueryStringValidator(regexp=None)[source]

Class for validation url query string, for example a=&b=1

Parameters:

regexp (typing.Optional[typing.Pattern]) –

vstutils.api.validators.resize_image(img, width, height)[source]

Utility function to resize image proportional to specific values. Can create white margins if it’s needed to satisfy required size

Parameters:
  • img (PIL.Image) – Pillow Image object

  • width (int) – Required width

  • height (int) – Required height

Returns:

Pillow Image object

Return type:

PIL.Image

vstutils.api.validators.resize_image_from_to(img, limits)[source]

Utility function to resize image proportional to values between min and max values for each side. Can create white margins if it’s needed to satisfy restrictions

Parameters:
  • img (PIL.Image) – Pillow Image object

  • limits (dict) – Dict with min/max side restrictions like: {'width': {'min': 300, 'max: 600'}, 'height':  {'min': 400, 'max: 800'}}

Returns:

Pillow Image object

Return type:

PIL.Image

Serializers

Default serializer classes for web-api. Read more in Django REST Framework documentation for Serializers.

class vstutils.api.serializers.BaseSerializer(*args, **kwargs)[source]

Default serializer with logic to work with objects.

This serializer serves as a base class for creating serializers to work with non-model objects. It extends the ‘rest_framework.serializers.Serializer’ class and includes additional logic for handling object creation and updating.

Note

You can set the generated_fields attribute in the Meta class to automatically include default CharField fields. You can also customize the field creation using the generated_field_factory attribute.

Example:

class MySerializer(BaseSerializer):
    class Meta:
        generated_fields = ['additional_field']
        generated_field_factory = lambda f: drf_fields.IntegerField()

In this example, the MySerializer class extends BaseSerializer and includes an additional generated field.

class vstutils.api.serializers.DisplayMode(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

For any serializer displayed on frontend property _display_mode can be set to one of this values.

DEFAULT = 'DEFAULT'

Will be used if no mode provided.

STEP = 'STEP'

Each properties group displayed as separate tab. On creation displayed as multiple steps.

class vstutils.api.serializers.EmptySerializer(*args, **kwargs)[source]

Default serializer for empty responses. In generated GUI this means that action button won’t show additional view before execution.

class vstutils.api.serializers.VSTSerializer(*args, **kwargs)[source]

Default model serializer based on rest_framework.serializers.ModelSerializer. Read more in DRF documentation how to create Model Serializers. This serializer matches model fields to extended set of serializer fields.

List of available pairs specified in VSTSerializer.serializer_field_mapping. For example, to set vstutils.api.fields.FkModelField in serializer use vstutils.models.fields.FkModelField in a model.

Example:

class MyModel(models.Model):
    name = models.CharField(max_length=255)

class MySerializer(VSTSerializer):
    class Meta:
        model = MyModel

In this example, the MySerializer class extends VSTSerializer and is associated with the MyModel model.

Views

VSTUtils extends the standard behavior of ViewSets from Django REST Framework (DRF) by providing built-in mechanisms for managing model views that cater to the most commonly encountered development patterns. This framework enhancement simplifies the process of creating robust and scalable web applications by offering a rich set of tools and utilities that automate much of the boilerplate code required in API development. Through these extensions, developers can easily implement custom business logic, data validation, and access control with minimal effort, thus significantly reducing development time and improving code maintainability.

class vstutils.api.base.CopyMixin(**kwargs)[source]

Mixin for viewsets which adds copy endpoint to view.

copy(request, **kwargs)[source]

Endpoint which copy instance with deps.

copy_field_name = 'name'

Name of field which will get a prefix.

copy_prefix = 'copy-'

Value of prefix which will be added to new instance name.

List of related names which will be copied to new instance.

class vstutils.api.base.FileResponseRetrieveMixin(**kwargs)[source]

ViewSet mixin for retrieving FileResponse from models with file fields data.

Example:

import datetime
import os
from django.db import models
from django.db.models.functions import Now
from rest_framework import permissions, fields as drf_fields
from vstutils.api.serializers import BaseSerializer, DataSerializer
from vstutils.models.decorators import register_view_action
from vstutils.models.custom_model import ListModel, FileModel, ViewCustomModel
from vstutils.api import fields, base, responses

from .cacheable import CachableModel


class TestQuerySerializer(BaseSerializer):
    test_value = drf_fields.ChoiceField(required=True, choices=("TEST1", "TEST2"))


class FileViewMixin(base.FileResponseRetrieveMixin):
    # required always
    instance_field_data = 'value'
    # required for response caching in browser
    instance_field_timestamp = 'updated'
    @register_view_action(
        methods=['get'],
        detail=False,
        query_serializer=TestQuerySerializer,
        serializer_class=DataSerializer,
        suffix='Instance'
    )
    def query_serializer_test(self, request):
        query_validated_data = self.get_query_serialized_data(request)
        return responses.HTTP_200_OK(query_validated_data)

    @register_view_action(
        methods=['get'],
        detail=False,
        query_serializer=TestQuerySerializer,
        is_list=True
    )
    def query_serializer_test_list(self, request):
        return self.list(request)
serializer_class_retrieve

alias of FileResponse

class vstutils.api.base.GenericViewSet(**kwargs)[source]

The base class for all views. Extends the standard features of the DRF class. Here are some of the possibilities:

  • Provides model attribute instead of queryset.

  • Provides to set serializers for each action separately through a dictionary action_serializers or attributes starting with serializer_class_[action name].

  • Provides to specify a serializer for lists and detail views separately.

  • Optimizes the database query for GET requests, if possible, by selecting only the fields necessary for the serializer.

create_action_serializer(*args, **kwargs)[source]

A method that implements the standard logic for actions. It relies on the passed arguments to build logic. So, if the named argument data was passed, then the serializer will be validated and saved.

Parameters:
  • autosave (bool) – Enables/disables the execution of saving by the serializer if named argument data passed. Enabled by default.

  • custom_data (dict) – Dict with data which will passed to validated_data without validation.

  • serializer_class (None,type[rest_framework.serializers.Serializer]) – Serializer class for this execution. May be useful when request and response serializers are different.

Param:

data: Default serializer class argument with serializable data. Enables validation and saving.

Param:

instance: Default serializer class argument with serializable instance.

Returns:

Ready serializer with default logic performed.

Return type:

rest_framework.serializers.Serializer

get_query_serialized_data(request, query_serializer=None, raise_exception=True)[source]

Get request query data and serialize values if query_serializer_class attribute exists or attribute was send.

Parameters:
  • request – DRF request object.

  • query_serializer – serializer class for processing parameters in query_params.

  • raise_exception – flag that indicates whether an exception should be thrown during validation in the serializer or not.

get_serializer(*args, **kwargs)[source]

Return the serializer instance that should be used for validating and deserializing input, and for serializing output.

Provide to use django.http.StreamingHttpResponse as serializer init.

get_serializer_class()[source]

Provides to setup serializer class for each action.

nested_allow_check()[source]

Just raise or pass. Used for nested views for easier access checking.

class vstutils.api.base.HistoryModelViewSet(**kwargs)[source]

Default viewset like ReadOnlyModelViewSet but for historical data (allow to delete, but can’t create and update). Inherited from GenericViewSet.

class vstutils.api.base.ModelViewSet(**kwargs)[source]

A viewset that provides CRUD actions under model. Inherited from GenericViewSet.

Variables:
Examples:
from vstutils.api.base import ModelViewSet
from . import serializers as sers


class StageViewSet(ModelViewSet):
    # This is difference with DRF:
    # we use model instead of queryset
    model = sers.models.Stage
    # Serializer for list view (view for a list of Model instances
    serializer_class = sers.StageSerializer
    # Serializer for page view (view for one Model instance).
    # This property is not required, if its value is the same as `serializer_class`.
    serializer_class_one = sers.StageSerializer
    # Allowed to set decorator to custom endpoint like this:
    # serializer_class_create - for create method
    # serializer_class_copy - for detail endpoint `copy`.
    # etc...
class vstutils.api.base.ReadOnlyModelViewSet(**kwargs)[source]

Default viewset like vstutils.api.base.ModelViewSet for readonly models. Inherited from GenericViewSet.

class vstutils.api.decorators.nested_view(name, arg=None, methods=None, *args, **kwargs)[source]

By default, DRF does not support nested views. This decorator solves this problem.

You need two or more models with nested relationship (Many-to-Many or Many-to-One) and two viewsets. Decorator nests viewset to parent viewset class and generate paths in API.

Parameters:
  • name (str) – Name of nested path. Also used as default name for related queryset (see manager_name).

  • arg (str) – Name of nested primary key field.

  • view (vstutils.api.base.ModelViewSet, vstutils.api.base.HistoryModelViewSet, vstutils.api.base.ReadOnlyModelViewSet) – Nested viewset class.

  • allow_append (bool) – Flag for allowing to append existed instances.

  • manager_name (str,Callable) – Name of model-object attr which contains nested queryset.

  • methods (list) – List of allowed methods to nested view endpoints.

  • subs (list,None) – List of allowed subviews or actions to nested view endpoints.

  • queryset_filters – List of callable objects which returns filtered queryset of main.

Note

Some view methods will not call for performance reasons. This also applies to some of the class attributes that are usually initialized in the methods. For example, .initial() will never call. Each viewset wrapped by nested class with additional logic.

Example:

from vstutils.api.decorators import nested_view
from vstutils.api.base import ModelViewSet
from . import serializers as sers


class StageViewSet(ModelViewSet):
    model = sers.models.Stage
    serializer_class = sers.StageSerializer


nested_view('stages', 'id', view=StageViewSet)
class TaskViewSet(ModelViewSet):
    model = sers.models.Task
    serializer_class = sers.TaskSerializer

This code generates api paths:

  • /tasks/ - GET, POST

  • /tasks/{id}/ - GET, PUT, PATCH, DELETE

  • /tasks/{id}/stages/ - GET, POST

  • /tasks/{id}/stages/{stages_id}/ - GET, PUT, PATCH, DELETE

vstutils.api.decorators.subaction(*args, **kwargs)[source]

Decorator which wrap object method to subaction of viewset.

Parameters:
  • methods – List of allowed HTTP-request methods. Default is ["post"].

  • detail – Flag to set method execution to one instance.

  • serializer_class – Serializer for this action.

  • permission_classes – Tuple or list permission classes.

  • url_path – API-path name for this action.

  • description – Description for this action in OpenAPI.

  • multiaction – Allow to use this action in multiactions. Works only with vstutils.api.serializers.EmptySerializer as response.

  • require_confirmation – Sets whether the action must be confirmed before being executed.

  • is_list – Mark this action as paginated list with all rules and parameters.

  • title – Override action title.

  • icons – Setup action icon classes.


An ETag (Entity Tag) is a mechanism defined by the HTTP protocol for web cache validation and to manage resource versions efficiently. It represents a unique identifier for the content of a resource at a given time, allowing client and server to determine if the resource has changed without downloading the entire content. This mechanism significantly reduces bandwidth and improves web performance by enabling conditional requests. Servers send ETags in responses to clients, which can cache these tags along with the resources. On subsequent requests, clients send the cached ETag back to the server in an If-None-Match header. If the resource has not changed (the ETag matches), the server responds with a 304 Not Modified status, indicating that the client’s cached version is up-to-date.

Beyond GET requests, ETags can also be instrumental in other HTTP methods like PUT or DELETE to ensure consistency and prevent unintended overwrites or deletions, known as “mid-air collision avoidance.” By including an ETag in the If-Match header of non-GET requests, clients signal that the operation should proceed only if the resource’s current state matches the specified ETag, thus safeguarding against concurrent modifications by different clients. This application of ETags enhances the reliability and integrity of web applications by ensuring that operations are performed on the correct version of a resource.

Here is main functionality provided for working with ETag’s mechanism:

class vstutils.api.base.CachableHeadMixin(**kwargs)[source]

A mixin designed to enhance caching for GET responses in Django REST framework views, leveraging the standard HTTP caching mechanism. It returns a 304 Not Modified status for reading requests like GET or HEAD when the ETag (Entity Tag) in the client’s request matches the current resource state, and a 412 Precondition Failed status for writing requests when the condition fails. This approach reduces unnecessary network traffic and load times for unchanged resources, and ensures data consistency for write operations.

The mixin relies on get_etag_value() and check_request_etag() functions within the GenericViewSet context to dynamically generate and validate ETags for resource states. By comparing ETags, it determines whether content has changed since the last request, allowing clients to reuse cached responses when applicable and preventing concurrent write operations from overwriting each other without acknowledgment of updated state.

Warning

This mixin is designed to work with models that inherit from vstutils.models.BModel. Usage with other models may not provide the intended caching behavior and could lead to incorrect application behavior.

Note

For effective use, ensure model classes are compatible with ETag generation and validation by implementing the get_etag_value() method for custom ETag computation. Additionally, the GenericViewSet using this mixin should properly handle ETag headers in client requests to leverage HTTP caching.

An additional feature of the CachableHeadMixin is its automatic inclusion in the generated view from a vstutils.models.BModel if the model class has the _cache_responses class attribute set to True. This enables automatic caching capabilities for models indicating readiness for HTTP-based caching, streamlining the process of optimizing response times and reducing server load for frequently accessed resources.

class vstutils.api.base.EtagDependency(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

A custom enumeration that defines potential dependencies for ETag generation. It includes:

LANG = 4

Indicates dependency on the user’s language preference.

SESSION = 2

Indicates dependency on the user’s session.

USER = 1

Indicates dependency on the user’s identity.

vstutils.api.base.check_request_etag(request, etag_value, header_name='If-None-Match', operation_handler=<slot wrapper '__eq__' of 'str' objects>)[source]

The function plays a crucial role within the context of the ETag mechanism, providing a flexible way to validate client-side ETags against the server-side version for both cache validation and ensuring data consistency in web applications. It supports conditional handling of HTTP requests based on the match or mismatch of ETag values, accommodating various scenarios such as cache freshness checks and prevention of concurrent modifications.

Parameters:
  • request (rest_framework.request.Request) – The HTTP request object containing the client’s headers, from which the ETag for comparison is retrieved.

  • etag_value (str) – The server-generated ETag value that represents the current state of the resource. This unique identifier is recalculated whenever the resource’s content changes.

  • header_name (str) – Specifies the HTTP header to look for the client’s ETag. Defaults to “If-None-Match”, commonly used in GET requests for cache validation. For operations requiring confirmation that the client is acting on the latest version of a resource (e.g., PUT or DELETE), “If-Match” should be used instead.

  • operation_handler – A function to compare the ETags. By default, this is set to str.__eq__, which checks for an exact match between the client’s and server’s ETags, suitable for validating caches with If-None-Match. To handle If-Match scenarios, where the operation should proceed only if the ETags do not match, indicating the resource has been modified, str.__ne__ (not equal) can be used as the operation handler. This flexibility allows for precise control over how and when clients are allowed to read from or write to resources based on their version.

Returns:

Returns a tuple containing the server’s ETag and a boolean flag. The flag is True if the operation handler condition between the server’s and client’s ETag is met, indicating the request should proceed based on the matching logic defined by the operation handler; otherwise, it returns False.

vstutils.api.base.get_etag_value(view, model_class, request, pk=None)[source]

The get_etag_value function is designed to compute a unique ETag value based on the model’s state, request parameters, and additional dependencies such as user language, session, and user identity. This function supports both single models and collections of models.

Parameters:
  • view (GenericViewSet) – An instance of GenericViewSet, responsible for view operations.

  • model_class (django.db.models.Model, list, tuple, or set) – The model class for which the ETag value is being generated. This parameter can be a single model class or a collection of model classes (list, tuple, or set). Each model class may optionally implement a class method named get_etag_value.

  • request (rest_framework.request.Request) – The request object from the Django REST framework, containing all the HTTP request information.

  • pk – he primary key of the model instance for which the ETag is being calculated. This can be a specific value (int or str) for single model usage, or a dictionary mapping model classes to their respective primary key values for collections of models.

Returns:

The computed ETag value as a hexadecimal string.

Return type:

str

The function operates differently based on the type of model_class provided:

  • Collection of Models: When model_class is a collection, the function computes an ETag by concatenating ETag values of individual models in the collection, using a recursive call for each model. The ETag value for each model is encoded and hashed using Blake2s algorithm.

  • Model with ``get_etag_value`` method: If the model class has a get_etag_value method, the function calls this method to obtain a base ETag value. It then appends language, user ID, and session key information if they are marked as dependencies in the model’s _cache_response_dependencies attribute. This base ETag may be further processed to include the application’s full version string and hashed if user or session information is included.

  • Model without ``get_etag_value`` method: For models lacking a custom get_etag_value method, the function generates an ETag based on the model’s class name and a hash of the application’s full version string.

Actions

Vstutils has the advanced system of working with actions. REST API works with data through verbs, which are called methods. However, to work with one or a list of entities, such actions may not be enough.

To expand the set of actions, you need to create an action that will work with some aspect of the described model. For these purposes, there is a standard rest_framework.decorators.action(), which can also be extended using the scheme. But for the greater convenience, there is a set of decorator objects in vstutils to eliminate the routine of writing boilerplate code.

The main philosophy for these wrappers is that the developer writes business logic without being distracted by the boilerplate code. Often, most of the errors in the code appear precisely because of the blurry look from the routine writing of the code.

class vstutils.api.actions.Action(detail=True, methods=None, serializer_class=<class 'vstutils.api.serializers.DataSerializer'>, result_serializer_class=None, query_serializer=None, multi=False, title=None, icons=None, is_list=False, hidden=False, require_confirmation=False, **kwargs)[source]

Base class of actions. Has minimal of required functionality to create an action and write only business logic. This decorator is suitable in cases where it is not possible to implement the logic using SimpleAction or the algorithm is much more complicated than standard CRUD.

Examples:

...
from vstutils.api.fields import VSTCharField
from vstutils.api.serializers import BaseSerializer
from vstutils.api.base import ModelViewSet
from vstutils.api.actions import Action
...

class RequestSerializer(BaseSerializer):
    data_field1 = ...
    ...


class ResponseSerializer(BaseSerializer):
    detail = VSTCharField(read_only=True)


class AuthorViewSet(ModelViewSet):
    model = ...
    ...

    @Action(serializer_class=RequestSerializer, result_serializer_class=ResponseSerializer, ...)
    def profile(self, request, *args, **kwargs):
        ''' Got `serializer_class` body and response with `result_serializer_class`. '''
        serializer = self.get_serializer(self.get_object(), data=request.data)
        serializer.is_valid(raise_exception=True)
        return {"detail": "Executed!"}
Parameters:
  • detail – Flag indicating which type of action is used: on a list or on a single entity. Affects where this action will be displayed - on a detailed record or on a list of records.

  • methods – List of available HTTP-methods for this action. Default has only POST method.

  • serializer_class – Request body serializer. Also used for default response.

  • result_serializer_class – Response body serializer. Required, when request and response has different set of fields.

  • query_serializer – GET-request query data serializer. It is used when it is necessary to get valid data in the query data of a GET-request and cast it to the required type.

  • multi – Used only with non-GET requests and notify GUI, that this action should be rendered over the selected list items.

  • title – Title for action in UI. For non-GET actions, title is generated from method’s name.

  • icons – List of icons for UI button.

  • is_list – Flag indicating whether the action type is a list or a single entity. Typically used with GET actions.

  • require_confirmation – If true user will be asked to confirm action execution on frontend.

  • kwargs – Set of named arguments for rest_framework.decorators.action().

class vstutils.api.actions.EmptyAction(**kwargs)[source]

In this case, actions on an object do not require any data and manipulations with them. For such cases, there is a standard method that allows you to simplify the scheme and code to work just with the object.

Optionally, you can also overload the response serializer to notify the interface about the format of the returned data.

Examples:

...
from vstutils.api.fields import RedirectIntegerField
from vstutils.api.serializers import BaseSerializer
from vstutils.api.base import ModelViewSet
from vstutils.api.actions import EmptyAction
...

class ResponseSerializer(BaseSerializer):
    id = RedirectIntegerField(operation_name='sync_history')


class AuthorViewSet(ModelViewSet):
    model = ...
    ...

    @EmptyAction(result_serializer_class=ResponseSerializer, ...)
    def sync_data(self, request, *args, **kwargs):
        ''' Example of action which get object, sync data and redirect user to another view. '''
        sync_id = self.get_object().sync().id
        return {"id": sync_id}
...
from django.http.response import FileResponse
from vstutils.api.base import ModelViewSet
from vstutils.api.actions import EmptyAction
...

class AuthorViewSet(ModelViewSet):
    model = ...
    ...

    @EmptyAction(result_serializer_class=ResponseSerializer, ...)
    def resume(self, request, *args, **kwargs):
        ''' Example of action which response with generated resume in pdf. '''
        instance = self.get_object()

        return FileResponse(
            streaming_content=instance.get_pdf(),
            as_attachment=True,
            filename=f'{instance.last_name}_{instance.first_name}_resume.pdf'
        )
class vstutils.api.actions.SimpleAction(*args, **kwargs)[source]

The idea of this decorator is to get the full CRUD for the instance in a minimum of steps. The instance is the object that was returned from the method being decorated. The whole mechanism is very similar to the standard property decorator, with a description of a getter, setter, and deleter.

If you’re going to create an entry point for working with a single object, then you do not need to define methods. The presence of a getter, setter, and deleter will determine which methods will be available.

In the official documentation of Django, an example is given with moving data that is not important for authorization to the Profile model. To work with such data that is outside the main model, there is this action object, which implements the basic logic in the most automated way.

It covers most of the tasks for working with such data. By default, it has a GET method instead of POST. Also, for better organization of the code, it allows you to change the methods that will be called when modifying or deleting data.

When assigning an action on an object, the list of methods is also filled with the necessary ones.

Examples:

...
from vstutils.api.fields import PhoneField
from vstutils.api.serializers import BaseSerializer
from vstutils.api.base import ModelViewSet
from vstutils.api.actions import Action
...

class ProfileSerializer(BaseSerializer):
    phone = PhoneField()


class AuthorViewSet(ModelViewSet):
    model = ...
    ...

    @SimpleAction(serializer_class=ProfileSerializer, ...)
    def profile(self, request, *args, **kwargs):
        ''' Get profile data to work. '''
        return self.get_object().profile

    @profile.setter
    def profile(self, instance, request, serializer, *args, **kwargs):
        instance.save(update_fields=['phone'])

    @profile.deleter
    def profile(self, instance, request, serializer, *args, **kwargs):
        instance.phone = ''
        instance.save(update_fields=['phone'])

Filtersets

For greater development convenience, the framework provides additional classes and functions for filtering elements by fields.

class vstutils.api.filters.DefaultIDFilter(data=None, queryset=None, *, request=None, prefix=None)[source]

Basic filterset to search by id. Provides a search for multiple values separated by commas. Uses extra_filter() in fields.

class vstutils.api.filters.DefaultNameFilter(data=None, queryset=None, *, request=None, prefix=None)[source]

Basic filterset to search by part of name. Uses LIKE DB condition by name_filter().

class vstutils.api.filters.FkFilterHandler(related_pk='id', related_name='name', pk_handler=<class 'int'>)[source]

Simple handler for filtering by relational fields.

Parameters:
  • related_pk (str) – Field name of related model’s primary key. Default is ‘id’.

  • related_name (str) – Field name of related model’s charfield. Default is ‘name’.

  • pk_handler (typing.Callable) – Changes handler for checking value before search. Sends “0” if handler falls. Default is ‘int()’.

Example:
class CustomFilterSet(filters.FilterSet):
    author = CharFilter(method=vst_filters.FkFilterHandler(related_pk='pk', related_name='email'))

Where author is ForeignKey to User and you want to search by primary key and email.

vstutils.api.filters.extra_filter(queryset, field, value)[source]

Method for searching values in a comma-separated list.

Parameters:
  • queryset (django.db.models.query.QuerySet) – model queryset for filtration.

  • field (str) – field name in FilterSet. Also supports __not suffix.

  • value (str) – comma separated list of searching values.

Returns:

filtered queryset.

Return type:

django.db.models.query.QuerySet

vstutils.api.filters.name_filter(queryset, field, value)[source]

Method for searching by part of name. Uses LIKE DB condition or contains qs-expression.

Parameters:
  • queryset (django.db.models.query.QuerySet) – model queryset for filtration.

  • field (str) – field name in FilterSet. Also supports __not suffix.

  • value (str) – searching part of name.

Returns:

filtered queryset.

Return type:

django.db.models.query.QuerySet

Responses

DRF provides a standard set of variables whose names correspond to the human-readable name of the HTTP code. For convenience, we have dynamically wrapped it in a set of classes that have appropriate names and additionally provides following capabilities:

  • String responses are wrapped in json like { "detail": "string response" }.

  • Attribute timings are kept for further processing in middleware.

  • Status code is set by class name (e.g. HTTP_200_OK or Response200 has code 200).

All classes inherit from:

class vstutils.api.responses.BaseResponseClass(*args, **kwargs)[source]

API response class with default status code.

Variables:
  • status_code (int) – HTTP status code.

  • timings (int,None) – Response timings.

Parameters:

timings – Response timings.

Middleware

By default, Django supposes that a developer creates Middleware class manually, but it’s often a routine. The vstutils library offers a convenient request handler class for elegant OOP development. Middleware is used to process incoming requests and send responses before they reach final destination.

class vstutils.middleware.BaseMiddleware(get_response)[source]

Middleware base class for handling:

Middleware must be added to MIDDLEWARE list in settings.

Example:
from vstutils.middleware import BaseMiddleware
from django.http import HttpResponse


class CustomMiddleware(BaseMiddleware):
    def request_handler(self, request):
        # Add header to request
        request.headers['User-Agent'] = 'Mozilla/5.0'
        return request

    def get_response_handler(self, request):
        if not request.user.is_stuff:
            # Return 403 HTTP status for non-stuff users.
            # This request never gets in any view.
            return HttpResponse(
                "Access denied!",
                content_type="text/plain",
                status_code=403
            )
        return super().get_response_handler(request)

    def handler(self, request, response):
        # Add header to response
        response['Custom-Header'] = 'Some value'
        return response
get_response_handler(request)[source]

Entrypoint for breaking or continuing request handling. This function must return django.http.HttpResponse object or result of parent class calling.

Since the release of 5.3, it has been possible to write this method as asynchronous. This should be used in cases where the middleware makes queries to the database or cache. However, such a middleware should be excluded from bulk requests.

Warning

Never do asynchronous middleware in dependent chains. They are designed to send independent requests to external sources.

Set async_capable to True and sync_capable to False for such middleware.

Parameters:

request (django.http.HttpRequest) – HTTP-request object which is wrapped from client request.

Return type:

django.http.HttpResponse

handler(request, response)[source]

The response handler. Method to process responses.

Parameters:
Returns:

Handled response object.

Return type:

django.http.HttpResponse

request_handler(request)[source]

The request handler. Called before request is handled by a view.

Parameters:

request (django.http.HttpRequest) – HTTP-request object which is wrapped from client request.

Returns:

Handled request object.

Return type:

django.http.HttpRequest

Filter Backends

Filter Backends are used to modify model queryset. To create custom filter backend to, (i.g. annotate model queryset), you should inherit from vstutils.api.filter_backends.VSTFilterBackend and override vstutils.api.filter_backends.VSTFilterBackend.filter_queryset() and in some cases vstutils.api.filter_backends.VSTFilterBackend.get_schema_fields().

class vstutils.api.filter_backends.DeepViewFilterBackend[source]

Backend that filters queryset by column from deep_parent_field property of the model. Value for filtering must be provided in query param __deep_parent.

If param is missing then no filtering is applied.

If param is empty value (/?__deep_parent=) then objects with no parent (the value of the field whose name is stored in the property deep_parent_field of the model is None) returned.

This filter backend and nested view is automatically added when model has deep_parent_field property.

Example:
from django.db import models
from vstutils.models import BModel

class DeepNestedModel(BModel):
    name = models.CharField(max_length=10)
    parent = models.ForeignKey('self', null=True, default=None, on_delete=models.CASCADE)

    deep_parent_field = 'parent'
    deep_parent_allow_append = True

    class Meta:
        default_related_name = 'deepnested'

In example above if we add this model under path ‘deep’, following views will be created: /deep/ and /deep/{id}/deepnested/.

Filter backend can be used as /deep/?__deep_parent=1 and will return all DeepNestedModel objects whose parent’s primary key is 1.

You can also use generic DRF views, for that you still must set deep_parent_field to your model and manually add DeepViewFilterBackend to filter_backends list.

class vstutils.api.filter_backends.HideHiddenFilterBackend[source]

Filter Backend that hides all objects with hidden=True from the queryset

filter_queryset(request, queryset, view)[source]

Clear objects with hidden attr from queryset.

class vstutils.api.filter_backends.SelectRelatedFilterBackend[source]

Filter Backend that will automatically call prefetch_related and select_related on all relations in queryset.

filter_queryset(request, queryset, view)[source]

Select+prefetch related in queryset.

class vstutils.api.filter_backends.VSTFilterBackend[source]

A base filter backend class to be inherited from. Example:

from django.utils import timezone
from django.db.models import Value, DateTimeField

from vstutils.api.filter_backends import VSTFilterBackend

class CurrentTimeFilterBackend(VSTFilterBackend):
    def filter_queryset(self, request, queryset, view):
        return queryset.annotate(current_time=Value(timezone.now(), output_field=DateTimeField()))

In this example Filter Backend annotates time in current timezone to any connected model’s queryset.

In some cases it may be necessary to provide a parameter from a query of request. To define this parameter in the schema, you must overload the get_schema_operation_parameters function and specify a list of parameters to use.

Example:

from django.utils import timezone
from django.db.models import Value, DateTimeField

from vstutils.api.filter_backends import VSTFilterBackend

class ConstantCurrentTimeForQueryFilterBackend(VSTFilterBackend):
    query_param = 'constant'

    def filter_queryset(self, request, queryset, view):
        if self.query_param in request.query_params and request.query_params[self.query_param]:
            queryset = queryset.annotate(**{
                request.query_params[self.query_param]: Value(timezone.now(), output_field=DateTimeField())
            })
        return queryset

        def get_schema_operation_parameters(self, view):
            return [
                {
                    "name": self.query_param,
                    "required": False,
                    "in": openapi.IN_QUERY,
                    "description": "Annotate value to queryset",
                    "schema": {
                        "type": openapi.TYPE_STRING,
                    }
                },
            ]

In this example Filter Backend annotates time in current timezone to any connected model’s queryset with field name from query constant.

get_schema_operation_parameters(view)[source]

You can also make the filter controls available to the schema autogeneration that REST framework provides, by implementing this method. The method should return a list of OpenAPI schema mappings.

Celery

Celery is a distributed task queue. It’s used to execute some actions asynchronously in a separate worker. For more details on Celery, check it’s official docs. For Celery related vstutils features to work, you need to specify [rpc] and [worker] sections in settings.ini. Also you need to include extra [rpc] requirements.

Tasks

class vstutils.tasks.TaskClass[source]

Wrapper for Celery BaseTask class. Usage is same as Celery standard class, but you can execute task without creating instance with TaskClass.do() method.

Example:

from vstutils.environment import get_celery_app
from vstutils.tasks import TaskClass

app = get_celery_app()

class Foo(TaskClass):
    def run(*args, **kwargs):
        return 'Foo task has been executed'

app.register_task(Foo())
Now you can call your task with various methods:
  • by executing Foo.do(*args, **kwargs)

  • get registered task instance like that - app.tasks[‘full_path.to.task.class.Foo’]

Also you can make your registered task periodic, by adding it to CELERY_BEAT_SCHEDULE in settings.py:

CELERY_BEAT_SCHEDULE = {
    'foo-execute-every-month': {
        'task': 'full_path.to.task.class.Foo',
        'schedule': crontab(day_of_month=1),
    },
}
classmethod do(*args, **kwargs)[source]

Method which send signal to celery for start remote task execution. All arguments will passed to the task TaskClass.run() method.

Return type:

celery.result.AsyncResult

property name

property for proper Celery task execution, needed for TaskClass.do() method to work

run(*args, **kwargs)

The body of the task executed by workers.

Endpoint

Endpoint view has two purposes: bulk requests execution and providing OpenAPI schema.

Endpoint url is /{API_URL}/endpoint/, for example value with default settings is /api/endpoint/.

API_URL can be changed in settings.py.

class vstutils.api.endpoint.EndpointViewSet(**kwargs)[source]

Default API-endpoint viewset.

get(request)[source]

Returns response with swagger ui or openapi json schema if ?format=openapi

Parameters:

request (vstutils.api.endpoint.BulkRequestType) –

Return type:

django.http.response.HttpResponse

get_client(request)[source]

Returns test client and guarantees that if bulk request comes authenticated than test client will be authenticated with the same user

Parameters:

request (vstutils.api.endpoint.BulkRequestType) –

Return type:

vstutils.api.endpoint.BulkClient

get_serializer(*args, **kwargs)[source]

Return the serializer instance that should be used for validating and deserializing input, and for serializing output.

Return type:

vstutils.api.endpoint.OperationSerializer

get_serializer_context(context)[source]

Extra context provided to the serializer class.

Return type:

dict

operate(operation_data, context)[source]

Method used to handle one operation and return result of it

Parameters:
Return type:

typing.Tuple[typing.Dict, typing.SupportsFloat]

post(request)[source]

Execute transactional bulk request

Parameters:

request (vstutils.api.endpoint.BulkRequestType) –

Return type:

vstutils.api.responses.BaseResponseClass

put(request, allow_fail=True)[source]

Execute non transaction bulk request

Parameters:

request (vstutils.api.endpoint.BulkRequestType) –

Return type:

vstutils.api.responses.BaseResponseClass

serializer_class

One operation serializer class.

alias of OperationSerializer

versioning_class

alias of QueryParameterVersioning

Bulk requests

Bulk request allows you send multiple requests to api at once, it accepts json list of operations.

Method

Transactional (all operations in one transaction)

Synchronous (operations executed one by one in given order)

PUT /{API_URL}/endpoint/

NO

YES

POST /{API_URL}/endpoint/

YES

YES

PATCH /{API_URL}/endpoint/

NO

NO

Parameters of one operation (required parameter marked by *):

  • method* - http method of request

  • path* - path of request, can be str or list

  • data - data to send

  • query - query parameters as str

  • let - string with name of variable (used for access to response result in templates)

  • headers - dict with headers which will be sent (key - header’s name, value - header’s value string).

  • version - str with specified version of api, if not provided then VST_API_VERSION will be used

Warning

In previous versions header’s names must follow CGI specification (e.g., CONTENT_TYPE, GATEWAY_INTERFACE, HTTP_*)

Since version 5.3 and after migrate to Django 4 names must follow HTTP specification instead of CGI.

In any request parameter you can insert result value of previous operations (<<{OPERATION_NUMBER or LET_VALUE}[path][to][value]>>), for example:

[
    {"method": "post", "path": "user", "data": {"name": "User 1"}),
    {"method": "delete", "version": "v2", "path": ["user", "<<0[data][id]>>"]}
]

Result of bulk request is json list of objects for operation:

  • method - http method

  • path - path of request, always str

  • data - data that needs to be sent

  • status - response status code

Transactional bulk request returns 502 BAG GATEWAY and does rollback after first failed request.

Warning

If you send non-transactional bulk request, you will get 200 status and must validate statuses on each operation responses.

OpenAPI schema

Request on GET /{API_URL}/endpoint/ returns Swagger UI.

Request on GET /{API_URL}/endpoint/?format=openapi returns OpenAPI schema in json format. Also you can specify required version of schema using version query parameter (e.g., GET /{API_URL}/endpoint/?format=openapi&version=v2).

To change the schema after generating and before sending to user use hooks. Define one or more function, each taking 2 named arguments:

  • request - user request object.

  • schema - ordered dict with OpenAPI schema.

Note

Sometimes hooks may raise an exception; in order to keep a chain of data modification, such exceptions are handled. The changes made to the schema before the exception however, are saved.

Example hook:
def hook_add_username_to_guiname(request, schema):
    schema['info']['title'] = f"{request.username} - {schema['info']['title']}"

To connect hook(s) to your app add function import name to the OPENAPI_HOOKS list in settings.py

OPENAPI_HOOKS = [
    '{{appName}}.openapi.hook_add_username_to_guiname',
]

Testing Framework

VST Utils Framework includes a helper in base test case class and improves support for making API requests. That means if you want make bulk request to endpoint you don’t need create and init test client, but just need to call:

endpoint_results = self.bulk([
    # list of endpoint requests
])

Creating test case

test.py module contains test case classes based on vstutils.tests.BaseTestCase. At the moment, we officially support two styles of writing tests: classic and simple query wrappers with run check and runtime optimized bulk queries with manual value checking.

Simple example with classic tests

For example, if you have api endpoint like /api/v1/project/ and model Project you can write test case like this:

from vstutils.tests import BaseTestCase


class ProjectTestCase(BaseTestCase):
    def setUp(self):
        super(ProjectTestCase, self).setUp()
        # init demo project
        self.initial_project = self.get_model_class('project.Test').objects.create(name="Test")

    def tearDown(self)
        super(ProjectTestCase, self).tearDown()
        # remove it after test
        self.initial_project.delete()

    def test_project_endpoint(self):
        # Test checks that api returns valid values
        self.list_test('/api/v1/project/', 1)
        self.details_test(
            ["project", self.initial_project.id],
            name=self.initial_project.name
        )
        # Try to create new projects and check list endpoint
        test_data = [
            {"name": f"TestProject{i}"}
            for i in range(2)
        ]
        id_list = self.mass_create("/api/v1/project/", test_data, 'name')
        self.list_test('/api/v1/project/', 1 + len(id_list))

This example demonstrates functionality of default test case class. Default projects are initialized for the fastest and most efficient result. We recommend to divide tests for different entities into different classes. This example demonstrate classic style of testing, but you can use bulks in your test cases.

Bulk requests in tests

Bulk query system is well suited for testing and executing valid queries. Previous example could be rewritten as follows:

from vstutils.tests import BaseTestCase


class ProjectTestCase(BaseTestCase):
    def setUp(self):
        super(ProjectTestCase, self).setUp()
        # init demo project
        self.initial_project = self.get_model_class('project.Test').objects.create(name="Test")

    def tearDown(self)
        super(ProjectTestCase, self).tearDown()
        # remove it after test
        self.initial_project.delete()

    def test_project_endpoint(self):
        test_data = [
            {"name": f"TestProject{i}"}
            for i in range(2)
        ]
        bulk_data = [
            {"method": "get", "path": ["project"]},
            {"method": "get", "path": ["project", self.initial_project.id]}
        ]
        bulk_data += [
            {"method": "post", "path": ["project"], "data": i}
            for i in test_data
        ]
        bulk_data.append(
            {"method": "get", "path": ["project"]}
        )
        results = self.bulk_transactional(bulk_data)

        self.assertEqual(results[0]['status'], 200)
        self.assertEqual(results[0]['data']['count'], 1)
        self.assertEqual(results[1]['status'], 200)
        self.assertEqual(results[1]['data']['name'], self.initial_project.name)

        for pos, result in enumerate(results[2:-1]):
            self.assertEqual(result['status'], 201)
            self.assertEqual(result['data']['name'], test_data[pos]['name'])

        self.assertEqual(results[-1]['status'], 200)
        self.assertEqual(results[-1]['data']['count'], 1 + len(test_data))

In this case, you have more code, but your tests are closer to GUI workflow, because vstutils-projects uses /api/endpoint/ for requests. Either way, bulk queries are much faster due to optimization; Testcase execution time is less comparing to non-bulk requests.

Test case API

class vstutils.tests.BaseTestCase(methodName='runTest')[source]

Main test case class extends django.test.TestCase.

assertCheckDict(first, second, msg=None)[source]

Fail if the two fields in dicts are unequal as determined by the ‘==’ operator. Checks if first not contains or not equal field in second

Parameters:
assertCount(iterable, count, msg=None)[source]

Calls len() over iterable and checks equality with count.

Parameters:
assertRCode(resp, code=200, *additional_info)[source]

Fail if response code is not equal. Message is response body.

Parameters:
bulk(data, code=200, **kwargs)[source]

Makes non-transactional bulk request and asserts status code (default is 200)

Parameters:
Return type:

typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray, typing.Dict, typing.Sequence[typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray]]]

Returns:

bulk response

bulk_transactional(data, code=200, **kwargs)[source]

Make transactional bulk request and assert status code (default is 200)

Parameters:
Return type:

typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray, typing.Dict, typing.Sequence[typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray]]]

Returns:

bulk response

call_registration(data, **kwargs)[source]

Function for calling registration. Just got form data and headers.

Parameters:
  • data (dict) – Registration form data.

  • kwargs – named arguments with request headers.

details_test(url, **kwargs)[source]

Test for get details of model. If you setup additional named arguments, the method check their equality with response data. Uses get_result() method.

Parameters:
  • url – url to detail record. For example: /api/v1/project/1/ (where 1 is uniq id of project). You can use get_url() for building url.

  • kwargs – params that’s should be checked (key - field name, value - field value).

endpoint_call(data=None, method='get', code=200, **kwargs)[source]

Makes request to endpoint and asserts response status code if specified (default is 200). Uses get_result() method for execution.

Parameters:
Return type:

typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray, typing.Dict, typing.Sequence[typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray]]]

Returns:

bulk response

endpoint_schema(**kwargs)[source]

Make request to schema. Returns dict with swagger data.

Parameters:

version – API version for schema parser.

get_count(model, **kwargs)[source]

Simple wrapper over get_model_filter() which returns counter of items.

Parameters:
Returns:

number of instances in database.

Return type:

int

get_model_class(model)[source]

Getting model class by string or return model arg.

Parameters:

model (str,django.db.models.Model) – string which contains model name (if attribute model is set to the test case class), module import, app.ModelName or django.db.models.Model.

Returns:

Model class.

Return type:

django.db.models.Model

get_model_filter(model, **kwargs)[source]

Simple wrapper over get_model_class() which returns filtered queryset from model.

Parameters:
Return type:

django.db.models.query.QuerySet

get_result(rtype, url, code=None, *args, **kwargs)[source]

Executes and tests response code on request with returning parsed result of request. The method uses the following procedure:

  • Test client authorization (with user which creates in setUp()).

  • Executing a request (sending args and kwargs to request method).

  • Parsing the result (converts json string to python-object).

  • Checking the http status code with assertRCode() (if you have not specified it, the code will be selected in accordance with the request method from the standard set std_codes).

  • Logout client.

  • Return parsed result.

Parameters:
  • rtype – request type (methods from Client cls): get, post etc.

  • url – requested url string or tuple for get_url(). You can use get_url() for url building or setup it as full string.

  • code (int) – expected return code from request.

  • relogin – execute force login and logout on each call. Default is True.

  • args – extra-args for Client class request method.

  • kwargs – extra-kwargs for Client class request method.

Return type:

typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray, typing.Dict, typing.Sequence[typing.Union[typing.List[typing.Dict[str, typing.Any]], str, bytes, bytearray]]]

Returns:

result of request.

get_url(*items)[source]

Function for creating url path based on VST_API_URL and VST_API_VERSION settings. Without arguments returns path to default version of api.

Return type:

str

Returns:

string like /api/v1/.../.../ where ... is args of function.

list_test(url, count)[source]

Test for get list of models. Checks only list count. Uses get_result() method.

Parameters:
  • url – url to abstract layer. For example: /api/v1/project/. You can use get_url() for building url.

  • count – count of objects in DB.

models = None

Attribute with default project models module.

classmethod patch(*args, **kwargs)[source]

Simple unittest.mock.patch() class-method wrapper.

Return type:

typing.ContextManager[unittest.mock.Mock]

classmethod patch_field_default(model, field_name, value)[source]

This method helps to path default value in the model’s field. It’s very useful for DateTime fields where django.utils.timezone.now() is used in defaults.

Parameters:
  • model (django.db.models.base.Model) –

  • field_name (str) –

  • value (typing.Any) –

Return type:

typing.ContextManager[unittest.mock.Mock]

random_name()[source]

Simple function which returns uuid1 string.

Return type:

str

std_codes: typing.Dict[str, int] = {'delete': 204, 'get': 200, 'patch': 200, 'post': 201}

Default http status codes for different http methods. Uses in get_result()

class user_as(testcase, user)[source]

Context for execute bulk or something as user. The context manager overrides self.user in TestCase and revert this changes on exit.

Parameters:

user (django.contrib.auth.models.AbstractUser) – new user object for execution.

Utils

This is tested set of development utilities. Utilities include a collection of code that will be useful in one way or another for developing the application. Vstutils uses mosts of these functions under the hood.

class vstutils.utils.BaseEnum(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

BaseEnum extends Enum class and used to create enum-like objects that can be used in django serializers or django models.

Example:

from vstutils.models import BModel

class ItemCLasses(BaseEnum):
    FIRST = BaseEnum.SAME
    SECOND = BaseEnum.SAME
    THIRD = BaseEnum.SAME


class MyDjangoModel(BModel):
    item_class = models.CharField(max_length=ItemCLasses.max_len, choices=ItemCLasses.to_choices())

    @property
    def is_second(self):
        # Function check is item has second class of instance
        return ItemCLasses.SECOND.is_equal(self.item_class)

Note

For special cases, when value must be in lower or upper case, you can setup value as BaseEnum.LOWER` or ``BaseEnum.UPPER. But in default cases we recommend use BaseEnum.SAME for memory optimization.

class vstutils.utils.BaseVstObject[source]

Default mixin-class for custom objects which needed to get settings and cache.

classmethod get_django_settings(name, default=None)[source]

Get params from Django settings.

Parameters:
  • name (str) – name of param

  • default (object) – default value of param

Returns:

Param from Django settings or default.

class vstutils.utils.Dict[source]

Wrapper over dict which return JSON on conversion to string.

class vstutils.utils.Executor(stdout=-1, stderr=-2, **environ_variables)[source]

Command executor with realtime output write and line handling. By default and by design executor initialize string attribute output which will be modified by += operator with new lines by Executor.write_output() procedure. Override the method if you want change behavior.

Executor class supports periodically (0.01 sec) handling process and execute some checks by overriding Executor.working_handler() procedure method. If you want disable this behavior override the method by None value or use UnhandledExecutor.

Parameters:

environ_variables (str) –

exception CalledProcessError(returncode, cmd, output=None, stderr=None)

Raised when run() is called with check=True and the process returns a non-zero exit status.

Attributes:

cmd, returncode, stdout, stderr, output

property stdout

Alias for output attribute, to match stderr

async aexecute(cmd, cwd, env=None)[source]

Executes commands and outputs its result. Asynchronous implementation.

Parameters:
  • cmd – – list of cmd command and arguments

  • cwd – – workdir for executions

  • env – – extra environment variables which overrides defaults

Returns:

– string with full output

execute(cmd, cwd, env=None)[source]

Executes commands and outputs its result.

Parameters:
  • cmd – – list of cmd command and arguments

  • cwd – – workdir for executions

  • env – – extra environment variables which overrides defaults

Returns:

– string with full output

async post_execute(cmd, cwd, env, return_code)[source]

Runs after execution end.

Parameters:
  • cmd – – list of cmd command and arguments

  • cwd – – workdir for executions

  • env – – extra environment variables which overrides defaults

  • return_code – – return code of executed process

async pre_execute(cmd, cwd, env)[source]

Runs before execution starts.

Parameters:
  • cmd – – list of cmd command and arguments

  • cwd – – workdir for executions

  • env – – extra environment variables which overrides defaults

async working_handler(proc)[source]

Additional handler for executions.

Parameters:

proc (asyncio.subprocess.Process) – running process

write_output(line)[source]
Parameters:

line (str) – – line from command output

Returns:

None

Return type:

None

class vstutils.utils.KVExchanger(key, timeout=None)[source]

Class for transmit data using key-value fast (cache-like) storage between services. Uses same cache-backend as Lock.

class vstutils.utils.Lock(id, payload=1, repeat=1, err_msg='', timeout=None)[source]

Lock class for multi-jobs workflow. Based on KVExchanger. The Lock allows only one thread to enter the part that’s locked and shared between apps using one locks cache (see also [locks]).

Parameters:
  • id (int,str) – – unique id for lock.

  • payload – – lock additional info. Should be any boolean True value.

  • repeat (int) – – time to wait lock.release. Default 1 sec.

  • err_msg (str) – – message for AcquireLockException error.

Note

  • Used django.core.cache lib and settings in settings.py

  • Have Lock.SCHEDULER and Lock.GLOBAL id

Example:
from vstutils.utils import Lock

with Lock("some_lock_identifier", repeat=30, err_msg="Locked by another proccess") as lock:
    # where
    # ``"some_lock_identifier"`` is unique id for lock and
    # ``30`` seconds lock is going wait until another process will release lock id.
    # After 30 sec waiting lock will raised with :class:`.Lock.AcquireLockException`
    # and ``err_msg`` value as text.
    some_code_execution()
    # ``lock`` object will has been automatically released after
    # exiting from context.
Another example without context manager:
from vstutils.utils import Lock

# locked block after locked object created
lock = Lock("some_lock_identifier", repeat=30, err_msg="Locked by another proccess")
# deleting of object calls ``lock.release()`` which release and remove lock from id.
del lock
exception AcquireLockException[source]

Exception which will be raised on unreleased lock.

class vstutils.utils.ModelHandlers(type_name, err_message=None)[source]

Handlers for some models like ‘INTEGRATIONS’ or ‘REPO_BACKENDS’. Based on ObjectHandlers but more specific for working with models. All handlers backends get by first argument model object.

Attributes:

Parameters:
  • objects (dict) – – dict of objects like: {<name>: <backend_class>}

  • keys (list) – – names of supported backends

  • values (list) – – supported backends classes

  • type_name – type name for backends.Like name in dict.

get_object(name, obj)[source]
Parameters:
Returns:

backend object

Return type:

object

class vstutils.utils.ObjectHandlers(type_name, err_message=None)[source]

Handlers wrapper for get objects from some settings structure.

Example:
from vstutils.utils import ObjectHandlers

'''
In `settings.py` you should write some structure:

SOME_HANDLERS = {
    "one": {
        "BACKEND": "full.python.path.to.module.SomeClass"
    },
    "two": {
        "BACKEND": "full.python.path.to.module.SomeAnotherClass",
        "OPTIONS": {
            "some_named_arg": "value"
        }
    }
}
'''

handlers = ObjectHandlers('SOME_HANDLERS')

# Get class handler for 'one'
one_backend_class = handlers['one']
# Get object of backend 'two'
two_obj = handlers.get_object()
# Get object of backend 'two' with overriding constructor named arg
two_obj_overrided = handlers.get_object(some_named_arg='another_value')
Parameters:

type_name (str) – type name for backends.Like name in dict.

backend(name)[source]

Get backend class

Parameters:

name (str) – – name of backend type

Returns:

class of backend

Return type:

type,types.ModuleType,object

class vstutils.utils.Paginator(qs, chunk_size=None)[source]

Class for fragmenting the query for small queries.

class vstutils.utils.SecurePickling(secure_key=None)[source]

Secured pickle wrapper by Vigenère cipher.

Warning

Do not use it with untrusted transport anyway.

Example:
from vstutils.utils import SecurePickling


serializer = SecurePickling('password')

# Init secret object
a = {"key": "value"}
# Serialize object with secret key
pickled = serializer.dumps(a)
# Deserialize object
unpickled = serializer.loads(pickled)

# Check, that object is correct
assert a == unpickled
class vstutils.utils.URLHandlers(type_name='URLS', *args, **kwargs)[source]

Object handler for GUI views. Uses GUI_VIEWS from settings.py. Based on ObjectHandlers but more specific to urlpatterns.

Example:
from vstutils.utils import URLHandlers


# By default gets from `GUI_VIEWS` in `settings.py`
urlpatterns = list(URLHandlers())
Parameters:

type_name – type name for backends.Like name in dict.

get_object(name, *argv, **kwargs)[source]

Get url object tuple for urls.py

Parameters:
  • name (str) – url regexp from

  • argv – overridden args

  • kwargs – overridden kwargs

Returns:

url object

Return type:

django.urls.re_path

class vstutils.utils.UnhandledExecutor(stdout=-1, stderr=-2, **environ_variables)[source]

Class based on Executor but disables working_handler.

Parameters:

environ_variables (str) –

class vstutils.utils.apply_decorators(*decorators)[source]

Decorator which apply list of decorators on method or class.

Example:
from vstutils.utils import apply_decorators

def decorator_one(func):
    print(f"Decorated {func.__name__} by first decorator.")
    return func

def decorator_two(func):
    print(f"Decorated {func.__name__} by second decorator.")
    return func

@apply_decorators(decorator_one, decorator_two)
def decorated_function():
    # Function decorated by both decorators.
    print("Function call.")
class vstutils.utils.classproperty(fget, fset=None)[source]

Decorator which makes class method as class property.

Example:
from vstutils.utils import classproperty

class SomeClass(metaclass=classproperty.meta):
    # Metaclass is needed for set attrs in class
    # instead of and not only object.

    some_value = None

    @classproperty
    def value(cls):
        return cls.some_value

    @value.setter
    def value(cls, new_value):
        cls.some_value = new_value
Parameters:
  • fget – function for getting an attribute value.

  • fset – function for setting an attribute value.

vstutils.utils.create_view(model, **meta_options)[source]

A simple function for getting the generated view by standard means, but with overloaded meta-parameters. This method can completely get rid of the creation of proxy models.

Example:
from vstutils.utils import create_view

from .models import Host

# Host model has full :class:`vstutils.api.base.ModelViewSet` view.
# For overriding and create simple list view just setup this:
HostListViewSet = create_view(
    HostList,
    view_class='list_only'
)

Note

This method is also recommended in cases where there is a problem of recursive imports.

Warning

This function is oldstyle and will be deprecated in future versions. Use native call of method :method:`vstutils.models.BModel.get_view_class`.

Parameters:

model (Type[vstutils.models.BaseModel]) – Model class with .get_view_class method. This method also has vstutils.models.BModel.

Return type:

vstutils.api.base.GenericViewSet

vstutils.utils.decode(key, enc)[source]

Decode string from encoded by Vigenère cipher.

Parameters:
  • key (str) – – secret key for encoding

  • enc (str) – – encoded string for decoding

Returns:

– decoded string

Return type:

str

vstutils.utils.deprecated(func)[source]

This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emitted when the function is used.

Parameters:

func – any callable that will be wrapped and will issue a deprecation warning when called.

vstutils.utils.encode(key, clear)[source]

Encode string by Vigenère cipher.

Parameters:
  • key (str) – – secret key for encoding

  • clear (str) – – clear value for encoding

Returns:

– encoded string

Return type:

str

vstutils.utils.get_render(name, data, trans='en')[source]

Render string from template.

Parameters:
  • name (str) – – full template name

  • data (dict) – – dict of rendered vars

  • trans (str) – – translation for render. Default ‘en’.

Returns:

– rendered string

Return type:

str

vstutils.utils.lazy_translate(text)[source]

The lazy_translate function has the same behavior as translate(), but wraps it in a lazy promise.

This is very useful, for example, for translating error messages in class attributes before the language code is known.

Parameters:

text – Text message which should be translated.

vstutils.utils.list_to_choices(items_list, response_type=<class 'list'>)[source]

Method to create django model choices from flat list of values.

Parameters:
  • items_list – list of flat values.

  • response_type – casting type of returned mapping

Returns:

list of tuples from items_list values

class vstutils.utils.model_lock_decorator(**kwargs)[source]

Decorator for functions where ‘pk’ kwarg exist for lock by id.

Warning

  • On locked error raised Lock.AcquireLockException

  • Method must have and called with pk named arg.

class vstutils.utils.raise_context(*args, **kwargs)[source]

Context for exclude exceptions.

class vstutils.utils.raise_context_decorator_with_default(*args, **kwargs)[source]

Context for exclude errors and return default value.

Example:
from yaml import load
from vstutils.utils import raise_context_decorator_with_default


@raise_context_decorator_with_default(default={})
def get_host_data(yaml_path, host):
    with open(yaml_path, 'r') as fd:
        data = load(fd.read(), Loader=Loader)
    return data[host]
    # This decorator used when you must return some value even on error
    # In log you also can see traceback for error if it occur

def clone_host_data(host):
    bs_data = get_host_data('inventories/aws/hosts.yml', 'build_server')
    ...
class vstutils.utils.redirect_stdany(new_stream=<_io.StringIO object>, streams=None)[source]

Context for redirect any output to own stream.

Note

  • On context returns stream object.

  • On exit returns old streams.

vstutils.utils.send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None, **kwargs)[source]

Wrapper over django.core.mail.send_mail() which provide additional named arguments.

vstutils.utils.send_template_email(sync=False, **kwargs)[source]

Function executing sync or async email sending; according sync argument and settings variable “RPC_ENABLED”. If you don’t set settings for celery or don’t have celery it sends synchronously mail. If celery is installed and configured and sync argument of the function is set to False, it sends asynchronously email.

Parameters:
  • sync – argument for determining how send email, asynchronously or synchronously

  • subject – mail subject.

  • email – list of strings or single string, with email addresses of recipients

  • template_name – relative path to template in templates directory, must include extension in file name.

  • context_data – dictionary with context for rendering message template.

vstutils.utils.send_template_email_handler(subject, email_from, email, template_name, context_data=None, **kwargs)[source]

Function for email sending. The function convert recipient to list and set context before sending if it possible.

Parameters:
  • subject – mail subject.

  • email_from – sender that be setup in email.

  • email – list of strings or single string, with email addresses of recipients

  • template_name – relative path to template in templates directory, must include extension in file name.

  • context_data – dictionary with context for rendering message template.

  • kwargs – additional named arguments for send_mail

Returns:

Number of emails sent.

class vstutils.utils.tmp_file(data='', mode='w', bufsize=-1, **kwargs)[source]

Temporary file with name generated and auto removed on close.

Attributes:

Parameters:
  • data (str) – – string to write in tmp file.

  • mode (str) – – file open mode. Default ‘w’.

  • bufsize (int) – – buffer size for tempfile.NamedTemporaryFile

  • kwargs – – other kwargs for tempfile.NamedTemporaryFile

write(wr_string)[source]

Write to file and flush

Parameters:

wr_string (str) – – writable string

Returns:

None

Return type:

None

class vstutils.utils.tmp_file_context(*args, **kwargs)[source]

Context object for work with tmp_file. Auto close on exit from context and remove if file still exist.

This context manager over tmp_file

vstutils.utils.translate(text)[source]

The translate function supports translation message dynamically with standard i18n vstutils’es mechanisms usage.

Uses django.utils.translation.get_language() to get the language code and tries to get the translation from the list of available ones.

Parameters:

text – Text message which should be translated.

Integrating Web Push Notifications

Web push notifications are an effective way to engage users with real-time messaging. To integrate web push notifications in your VSTUtils project, follow these steps:

  1. Configuration: First, include the vstutils.webpush module in the INSTALLED_APPS section of your settings.py file. This enables the web push functionality provided by VSTUtils. Additionally, configure the necessary settings as described in the web push settings section (see here for details).

  2. Creating Notifications: To create a web push notification, you need to define a class that inherits from either vstutils.webpush.BaseWebPush or vstutils.webpush.BaseWebPushNotification. VSTUtils automatically detects and utilizes web push classes defined in the webpushes module of all INSTALLED_APPS. Below is an example that illustrates how to implement custom web push classes:

     1from vstutils.api.models import Language
     2from vstutils.webpush.base import BaseWebPush, BaseWebPushNotification
     3from vstutils.webpush.models import WebPushDeviceSubscription, WebPushNotificationSubscription
     4
     5
     6class TestWebPush(BaseWebPush):
     7    """
     8    Webpush that is sent to all subscribed users
     9    """
    10
    11    def get_subscriptions(self):
    12        return WebPushDeviceSubscription.objects.filter(
    13            user_id__in=WebPushNotificationSubscription.objects.filter(
    14                type=self.get_key(),
    15                enabled=True,
    16            ).values('user_id'),
    17        )
    18
    19    def get_payload(self, lang: Language):
    20        return {"some": "data", "lang": lang.code}
    21
    22
    23class TestNotification(BaseWebPushNotification):
    24    """
    25    Webpush notification that is sent only to selected users
    26    """
    27
    28    def __init__(self, name: str, user_id: int):
    29        self.name = name
    30        self.user_id = user_id
    31        self.message = f"Hello {self.name}"
    32
    33    def get_users_ids(self):
    34        return (self.user_id,)
    35
    36    def get_notification(self, lang: Language):
    37        return {
    38            "title": self.message,
    39            "options": {
    40                "body": "Test notification body",
    41                "data": {"url": "/"},
    42            },
    43        }
    44
    45
    46class StaffOnlyNotification(BaseWebPushNotification):
    47    """
    48    Webpush notification that only staff user can subscribe to.
    49    """
    50
    51    @staticmethod
    52    def is_available(user):
    53        return user.is_staff
    

    This example contains three classes:

    • TestWebPush: Sends notifications to all subscribed users.

    • TestNotification: Targets notifications to specific users.

    • StaffOnlyNotification: Restricts notifications to staff users only. Sometimes you may want to allow only some users to subscribe on specific notifications.

  3. Sending Notifications: To dispatch a web push notification, invoke the send or send_in_task method on an instance of your web push class. For instance, to send a notification using TestNotification, you can do the following:

    from test_proj.webpushes import TestNotification
    
    # Sending a notification immediately (synchronously)
    TestNotification(name='Some user', user_id=1).send()
    
    # Sending a notification as a background task (asynchronously)
    TestNotification.send_in_task(name='Some user', user_id=1)
    

Warning

The asynchronous sending of web push notifications (using methods like send_in_task) requires a configured Celery setup in your project, as it relies on Celery tasks “under the hood”. Ensure that Celery is properly set up and running to utilize asynchronous notification dispatching.

By following these steps, you can fast integrate and utilize web push notifications in projects with VSTUtils.