Skip to content

Instantly share code, notes, and snippets.

@gimntut
Created September 28, 2024 09:09
Show Gist options
  • Save gimntut/6e9241b7b4b92ee79de7fa8b3f88a8f4 to your computer and use it in GitHub Desktop.
Save gimntut/6e9241b7b4b92ee79de7fa8b3f88a8f4 to your computer and use it in GitHub Desktop.
from typing import Type, TYPE_CHECKING, TypeVar
from django.utils import timezone
from rest_framework.fields import Field
from rest_framework.serializers import ListSerializer
T = TypeVar("T")
def mixin_for(_: T) -> T:
# https://dev.to/gimntut/-1ohb
return object
class DataSerializerField(Field):
"""Сериализатор для вычисляемых данных"""
def __new__(
cls, serializer: Type["SerializerType"], *args, method_name=None, **kwargs
) -> "SerializerType":
class GetAttributeMixin(mixin_for(Field)):
def get_attribute(self, instance):
if self.source_attrs:
value = super().get_attribute(instance)
else:
default_method_name = f"get_{self.field_name}_data"
attr_name = method_name or default_method_name
method = getattr(self.parent, attr_name, None)
if not method:
raise AttributeError(
f"Не найден метод {attr_name} в классе {type(self.parent).__name__}"
)
value = method(instance)
return value
class_name = f'{serializer.__name__.replace("Serializer", "")}DataSerializer'
list_serializer_class = type("DataListSerializer", (GetAttributeMixin, ListSerializer), {})
parent_meta_class = getattr(serializer, "Meta", object)
ref_name = class_name + str(int(timezone.now().timestamp() * 100000))
meta_class = type(
"Meta",
(parent_meta_class,),
{"list_serializer_class": list_serializer_class, "ref_name": ref_name},
)
data_serializer_class = type(
class_name, (GetAttributeMixin, serializer), {"Meta": meta_class}
)
kwargs.setdefault("source", "*")
kwargs["read_only"] = True
kwargs["required"] = False
return data_serializer_class(**kwargs)
if TYPE_CHECKING:
from utils.api.typing import SerializerType
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment