Игорь Надеин 4f6244ab1f
Some checks failed
Deploy production / deploy (push) Failing after 2s
Fix CORP runtime errors and harden deployment and media access
2026-09-10 16:40:08 +03:00

117 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# api/v1/documents/fields.py
"""
Кастомные serializer fields для работы с django-filer.
"""
import logging
from django.core.files.uploadedfile import UploadedFile
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from filer.models import File as FilerFile
from rest_framework import serializers
logger = logging.getLogger(__name__)
@extend_schema_field(OpenApiTypes.BINARY)
class FilerFileField(serializers.Field):
"""
Serializer field для работы с django-filer FilerFileField.
При чтении (GET):
- Возвращает URL файла из filer.File.url
При записи (POST/PUT/PATCH):
- Принимает UploadedFile
- Создает filer.File объект
- Возвращает filer.File instance для присвоения в модель
"""
def to_representation(self, value):
"""
Преобразует filer.File в URL для API response.
Args:
value: filer.File instance или None
Returns:
str: Полный URL файла или None
"""
if value is None:
return None
if isinstance(value, FilerFile):
if not value.url:
return None
# Получаем request из контекста для построения абсолютного URL
request = self.context.get("request")
if request:
return request.build_absolute_uri(value.url)
# Fallback: возвращаем относительный URL
return value.url
return None
def to_internal_value(self, data):
"""
Преобразует UploadedFile в filer.File instance.
Args:
data: UploadedFile из request
Returns:
FilerFile: Созданный filer.File объект
Raises:
serializers.ValidationError: При ошибках валидации
"""
if data is None:
return None
if not isinstance(data, UploadedFile):
raise serializers.ValidationError("Ожидается файл для загрузки.")
# Получаем пользователя из контекста
request = self.context.get("request")
owner = getattr(request, "user", None) if request else None
try:
# Создаем filer.File объект
# Downloads go through the Document API and its audience/object ACL.
# A filer public URL must never bypass those permissions.
filer_file = FilerFile.objects.create(
file=data,
original_filename=data.name,
name=data.name,
owner=owner,
is_public=False,
)
logger.info(
"Document file created",
extra={
"event": "document.file.created",
"file_id": filer_file.id,
"owner_id": owner.id if owner else None,
"is_public": False,
"size_bytes": data.size,
},
)
return filer_file
except Exception as e:
logger.exception(
"Document file creation failed",
extra={
"event": "document.file.creation_failed",
"owner_id": owner.id if owner else None,
"size_bytes": data.size,
"error_type": type(e).__name__,
},
)
raise serializers.ValidationError(f"Ошибка при создании файла: {str(e)}")