diff --git a/frontend_src/vstutils/fetch-values.ts b/frontend_src/vstutils/fetch-values.ts index 89958abb..6a6cb0fd 100644 --- a/frontend_src/vstutils/fetch-values.ts +++ b/frontend_src/vstutils/fetch-values.ts @@ -87,6 +87,7 @@ function fetchInstancesFields(instances: Model[], fields: Field[], options?: Opt } else if (field instanceof ArrayField) { promises.push(fetchArrayFieldValues(field as ArrayField, instances, options)); } else if (field instanceof DynamicField) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument promises.push(fetchDynamicFieldValues(field, instances, options)); } else if (field instanceof RelatedListField) { promises.push(fetchRelatedListFieldValues(field, instances, options)); diff --git a/frontend_src/vstutils/fields/dynamic/DependFromFkField.ts b/frontend_src/vstutils/fields/dynamic/DependFromFkField.ts index 63619149..9ac23228 100644 --- a/frontend_src/vstutils/fields/dynamic/DependFromFkField.ts +++ b/frontend_src/vstutils/fields/dynamic/DependFromFkField.ts @@ -1,72 +1,40 @@ -import { BaseField } from '@/vstutils/fields/base'; -import { mergeDeep } from '@/vstutils/utils'; import DependFromFkFieldMixin from './DependFromFkFieldMixin.vue'; -import type { Field, FieldOptions, FieldXOptions } from '@/vstutils/fields/base'; -import type { InnerData, RepresentData } from '@/vstutils/utils'; +import type { FieldOptions } from '@/vstutils/fields/base'; +import type { DynamicFieldXOptions } from './DynamicField'; +import { DynamicField } from './DynamicField'; -interface XOptions extends FieldXOptions { +interface XOptions extends DynamicFieldXOptions { field: string; field_attribute: string; callback?: (data: Record) => Record; } -export class DependFromFkField extends BaseField { +export class DependFromFkField extends DynamicField { dependField: string; dependFieldAttribute: string; - /** - * Function that is used to customize real field options - */ - callback?: (data: Record) => Record; - constructor(options: FieldOptions) { super(options); this.dependField = this.props.field; this.dependFieldAttribute = this.props.field_attribute; - this.callback = this.props.callback; } static get mixins() { - return [DependFromFkFieldMixin]; - } - - toInner(data: RepresentData) { - return this.getRealField(data).toInner(data); - } - - toRepresent(data: InnerData) { - return this.getRealField(data).toRepresent(data); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return [DependFromFkFieldMixin as any]; } - validateValue(data: RepresentData) { - return this.getRealField(data).validateValue(data); - } - - getFieldByFormat(format: Record | string, data: Record): Field { - let callback_opt: Record = {}; - if (this.callback) { - callback_opt = this.callback(data); - } - const realField = this.app.fieldsResolver.resolveField( - mergeDeep({ format, callback_opt }), - this.name, - ); - if (!realField.model && this.model) { - realField.model = this.model; - } - if (this.app.store.page) { - realField.prepareFieldForView(this.app.store.page.view.path); - } - return realField; - } - - getRealField(data: Record): Field { + _getParentValues(data: Record = {}): Record { const dependFromInstance = data[this.dependField] as Record | undefined; const dependFieldValue = (dependFromInstance?.[this.dependFieldAttribute] || 'string') as | Record | string; - return this.getFieldByFormat(dependFieldValue, data); + return { [this.dependFieldAttribute]: dependFieldValue }; + } + + _getFromValue(data: Record) { + return this.getFieldByDefinition({ format: data[this.dependFieldAttribute] as string }); } } diff --git a/frontend_src/vstutils/fields/dynamic/DynamicField.ts b/frontend_src/vstutils/fields/dynamic/DynamicField.ts index de46fa8e..527c337c 100644 --- a/frontend_src/vstutils/fields/dynamic/DynamicField.ts +++ b/frontend_src/vstutils/fields/dynamic/DynamicField.ts @@ -8,7 +8,7 @@ import type { FieldDefinition } from '@/vstutils/fields/FieldsResolver'; import type { PageView, BaseView } from '@/vstutils/views'; import type { InnerData, RepresentData } from '@/vstutils/utils'; -interface DynamicFieldXOptions extends FieldXOptions { +export interface DynamicFieldXOptions extends FieldXOptions { source_view?: string; field?: string | string[]; types?: Record; @@ -16,15 +16,15 @@ interface DynamicFieldXOptions extends FieldXOptions { callback?: (data: Record) => FieldDefinition | undefined; } -export class DynamicField - extends BaseField - implements Field +export class DynamicField + extends BaseField + implements Field { types: Record | null = null; usedOnViews = new Set(); sourceView?: PageView | number; - constructor(options: FieldOptions) { + constructor(options: FieldOptions) { super(options); onAppAfterInit(() => { diff --git a/frontend_src/vstutils/fields/dynamic/__tests__/DependFromFkField.test.js b/frontend_src/vstutils/fields/dynamic/__tests__/DependFromFkField.test.js index dd3cd36c..cc8fa2f9 100644 --- a/frontend_src/vstutils/fields/dynamic/__tests__/DependFromFkField.test.js +++ b/frontend_src/vstutils/fields/dynamic/__tests__/DependFromFkField.test.js @@ -84,6 +84,9 @@ const schema = createSchema({ 'x-options': { field: 'key', field_attribute: 'field_type', + types: { + complex_field: { type: 'boolean' }, + }, }, }, }, @@ -217,7 +220,7 @@ describe('DependFromFkField', () => { results: [ { id: 1, - field_type: 'boolean', + field_type: 'complex_field', }, ], }, diff --git a/requirements-rpc.txt b/requirements-rpc.txt index cff5b5ca..13f3ffb7 100644 --- a/requirements-rpc.txt +++ b/requirements-rpc.txt @@ -1,3 +1,3 @@ # Packages needed for delayed jobs. -celery[redis]==5.3.5 +celery[redis]==5.3.6 django-celery-beat~=2.5.0 diff --git a/requirements.txt b/requirements.txt index c23ee7f9..ac0cf7c1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ django-environ~=0.11.2 # REST API packages djangorestframework~=3.14.0 drf-yasg==1.21.7 -django-filter==23.3 +django-filter==23.4 drf_orjson_renderer==1.7.1 ormsgpack~=1.4.1 pyyaml~=6.0.1 diff --git a/test_src/test_proj/tests.py b/test_src/test_proj/tests.py index a62fc0bc..7e81eea2 100644 --- a/test_src/test_proj/tests.py +++ b/test_src/test_proj/tests.py @@ -1929,7 +1929,7 @@ def test_openapi_schema_content(self): self.assertEqual(api['definitions']['Variable']['properties']['value']['format'], 'dynamic_fk') self.assertEqual( api['definitions']['Variable']['properties']['value'][X_OPTIONS], - {"field": 'key', 'field_attribute': 'val_type'} + {"field": 'key', 'field_attribute': 'val_type', 'types': {}} ) # Check that's schema is correct and fields are working diff --git a/vstutils/__init__.py b/vstutils/__init__.py index 667dc189..95b6b272 100644 --- a/vstutils/__init__.py +++ b/vstutils/__init__.py @@ -1,2 +1,2 @@ # pylint: disable=django-not-available -__version__: str = '5.8.16' +__version__: str = '5.8.17' diff --git a/vstutils/api/doc_generator.py b/vstutils/api/doc_generator.py index 5d7571ca..348457aa 100644 --- a/vstutils/api/doc_generator.py +++ b/vstutils/api/doc_generator.py @@ -16,9 +16,9 @@ class _YamlOrderedLoader(yaml.SafeLoader): pass -_YamlOrderedLoader.add_constructor( # type: ignore +_YamlOrderedLoader.add_constructor( yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, - lambda loader, node: collections.OrderedDict(loader.construct_pairs(node)) # type: ignore + lambda loader, node: collections.OrderedDict(loader.construct_pairs(node)) ) diff --git a/vstutils/api/fields.py b/vstutils/api/fields.py index 9353d1a4..ad727eea 100644 --- a/vstutils/api/fields.py +++ b/vstutils/api/fields.py @@ -261,7 +261,7 @@ class DynamicJsonTypeField(VSTCharField): :type field: str :param types: key-value mapping where key is value of subscribed field and value is type (in OpenAPI format) of current field. - :type type: dict + :type types: dict :param choices: 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. @@ -371,6 +371,9 @@ class DependFromFkField(DynamicJsonTypeField): :type field: str :param field_attribute: attribute of related model instance with name of type. :type field_attribute: str + :param types: key-value mapping where key is value of subscribed field and + value is type (in OpenAPI format) of current field. + :type types: dict .. warning:: ``field_attribute`` in related model must be :class:`rest_framework.fields.ChoicesField` or @@ -381,9 +384,8 @@ class DependFromFkField(DynamicJsonTypeField): default_related_field = VSTCharField(allow_null=True, allow_blank=True, default='') def __init__(self, **kwargs): - self.field = kwargs.pop('field') self.field_attribute = kwargs.pop('field_attribute') - super(DynamicJsonTypeField, self).__init__(**kwargs) # pylint: disable=bad-super-call + super().__init__(**kwargs) # pylint: disable=bad-super-call def get_value(self, dictionary: _t.Any) -> _t.Any: value = super().get_value(dictionary) diff --git a/vstutils/api/models.py b/vstutils/api/models.py index 9d1dc3a4..9e614998 100644 --- a/vstutils/api/models.py +++ b/vstutils/api/models.py @@ -31,7 +31,7 @@ def get_etag_value(cls, pk=None): hashable_str = '_'.join(c for c, _ in settings.LANGUAGES) + (f'_{pk}' if pk is not None else '') if settings.ENABLE_CUSTOM_TRANSLATIONS: hashable_str += CustomTranslations.get_etag_value(pk) - return hashlib.md5(hashable_str.encode('utf-8')).hexdigest() + return hashlib.md5(hashable_str.encode('utf-8')).hexdigest() # nosec def _get_translation_data(self, module_path_string, code, for_server=False): data = {} diff --git a/vstutils/api/schema/info.py b/vstutils/api/schema/info.py index 9fa9b185..73c7e015 100644 --- a/vstutils/api/schema/info.py +++ b/vstutils/api/schema/info.py @@ -4,7 +4,7 @@ import django from django.conf import settings from django.urls import reverse_lazy -from rest_framework import __version__ as drf_version # type: ignore +from rest_framework import __version__ as drf_version from fastapi import __version__ as fastapi_version from drf_yasg import openapi, __version__ as drf_yasg_version # type: ignore try: diff --git a/vstutils/api/schema/inspectors.py b/vstutils/api/schema/inspectors.py index 7d6c85ff..c9702e8d 100644 --- a/vstutils/api/schema/inspectors.py +++ b/vstutils/api/schema/inspectors.py @@ -201,17 +201,17 @@ def field_to_swagger_object(self, field, swagger_object_type, use_references, ** if isinstance(field, fields.DependFromFkField): field_format = FORMAT_DYN_FK options['field_attribute'] = field.field_attribute - else: field_format = FORMAT_DYN if field.source_view: options['source_view'] = field.source_view options['choices'] = field.choices - options['types'] = {} - for name, field_type in field.types.items(): - if isinstance(field_type, Field): - field_type = self.probe_field_inspectors(field_type, swagger_object_type, False) - options['types'][name] = field_type + + options['types'] = {} + for name, field_type in field.types.items(): + if isinstance(field_type, Field): + field_type = self.probe_field_inspectors(field_type, swagger_object_type, False) + options['types'][name] = field_type kwargs = { 'type': openapi.TYPE_STRING, diff --git a/vstutils/templatetags/vst_gravatar.py b/vstutils/templatetags/vst_gravatar.py index f5a9ffdc..e9a2521c 100644 --- a/vstutils/templatetags/vst_gravatar.py +++ b/vstutils/templatetags/vst_gravatar.py @@ -31,5 +31,5 @@ def get_user_gravatar(user_id): if not user.email: return static('img/anonymous.png') url_base = 'https://www.gravatar.com/avatar/{}?d=mp' - user_hash = hashlib.md5(user.email.lower().encode('utf-8')).hexdigest() + user_hash = hashlib.md5(user.email.lower().encode('utf-8')).hexdigest() # nosec return url_base.format(user_hash) diff --git a/vstutils/utils.pyi b/vstutils/utils.pyi index 50bb2bc7..f7a66c51 100644 --- a/vstutils/utils.pyi +++ b/vstutils/utils.pyi @@ -474,7 +474,7 @@ class StaticFilesHandlers(ObjectHandlers): class ModelHandlers(ObjectHandlers): - def get_object(self, name: tp.Text, obj) -> tp.Any: # type: ignore[override] + def get_object(self, name: tp.Text, obj) -> tp.Any: ...