uchill/backend/apps/materials/serializers.py

303 lines
9.3 KiB
Python
Raw 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.

"""
Сериализаторы для учебных материалов.
"""
from rest_framework import serializers
from django.db import models
from .models import Material, MaterialFolder, MaterialTag, MaterialAccess, StorageQuota
from apps.users.serializers import UserSerializer
class MaterialTagSerializer(serializers.ModelSerializer):
"""Сериализатор тега."""
class Meta:
model = MaterialTag
fields = [
'id',
'name',
'slug',
'color',
'materials_count'
]
read_only_fields = ['materials_count']
class MaterialFolderSerializer(serializers.ModelSerializer):
"""Сериализатор папки."""
owner = UserSerializer(read_only=True)
path = serializers.SerializerMethodField()
class Meta:
model = MaterialFolder
fields = [
'id',
'name',
'description',
'owner',
'parent',
'path',
'is_public',
'materials_count',
'created_at',
'updated_at'
]
read_only_fields = ['owner', 'materials_count', 'created_at', 'updated_at']
def get_path(self, obj):
"""Получить путь папки."""
return obj.get_path()
class MaterialSerializer(serializers.ModelSerializer):
"""Сериализатор материала."""
owner = UserSerializer(read_only=True)
folder = MaterialFolderSerializer(read_only=True)
tags = MaterialTagSerializer(many=True, read_only=True)
shared_with = UserSerializer(many=True, read_only=True)
class Meta:
model = Material
fields = [
'id',
'title',
'description',
'file',
'file_name',
'file_size',
'file_type',
'url',
'material_type',
'owner',
'folder',
'tags',
'lesson',
'homework',
'access_type',
'allow_download',
'is_featured',
'shared_with',
'views_count',
'downloads_count',
'created_at',
'updated_at'
]
read_only_fields = [
'owner',
'file_name',
'file_size',
'file_type',
'views_count',
'downloads_count',
'created_at',
'updated_at'
]
class MaterialListSerializer(serializers.ModelSerializer):
"""Сериализатор списка материалов (упрощенный)."""
owner = UserSerializer(read_only=True)
tags = MaterialTagSerializer(many=True, read_only=True)
file_url = serializers.SerializerMethodField()
class Meta:
model = Material
fields = [
'id',
'title',
'description',
'file',
'file_url',
'file_name',
'file_size',
'file_type',
'url',
'material_type',
'owner',
'folder',
'tags',
'access_type',
'is_featured',
'views_count',
'created_at'
]
def get_file_url(self, obj):
"""Полный URL файла для превью (изображения, видео)."""
if obj.file:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.file.url)
return obj.file.url
return None
class MaterialCreateSerializer(serializers.ModelSerializer):
"""Сериализатор создания материала."""
folder_id = serializers.IntegerField(required=False, allow_null=True)
tag_ids = serializers.ListField(
child=serializers.IntegerField(),
required=False,
allow_empty=True
)
class Meta:
model = Material
fields = [
'title',
'description',
'file',
'url',
'material_type',
'folder_id',
'tag_ids',
'lesson',
'homework',
'access_type',
'allow_download',
'is_featured'
]
def validate(self, attrs):
"""Валидация."""
from .services import StorageService
# Проверяем что указан file или url
if not attrs.get('file') and not attrs.get('url'):
raise serializers.ValidationError({
'file': 'Необходимо указать файл или ссылку'
})
# Проверяем квоту если загружается файл
if attrs.get('file'):
user = self.context['request'].user
file_size = attrs['file'].size
# Используем сервис для проверки лимита
can_upload, error_message, warning_message = StorageService.check_storage_limit(user, file_size)
if not can_upload:
raise serializers.ValidationError({
'file': error_message
})
# Сохраняем предупреждение в контексте для использования в create
if warning_message:
self.context['storage_warning'] = warning_message
return attrs
def create(self, validated_data):
"""Создание материала."""
folder_id = validated_data.pop('folder_id', None)
tag_ids = validated_data.pop('tag_ids', [])
user = self.context['request'].user
# Получаем информацию о файле
file = validated_data.get('file')
if file:
validated_data['file_name'] = file.name
validated_data['file_size'] = file.size
validated_data['file_type'] = file.content_type
# Создаем материал с owner (owner будет переопределен в perform_create, но нужен для создания)
material = Material.objects.create(
owner=user,
folder_id=folder_id,
**validated_data
)
# Добавляем теги
if tag_ids:
tags = MaterialTag.objects.filter(id__in=tag_ids)
material.tags.set(tags)
# Обновляем квоту если загружен файл
if file:
from .services import StorageService
StorageService.add_file_usage(user, file.size)
return material
class StorageQuotaSerializer(serializers.ModelSerializer):
"""Сериализатор квоты хранилища."""
user = UserSerializer(read_only=True)
used_percentage = serializers.SerializerMethodField()
available_space = serializers.SerializerMethodField()
total_quota_mb = serializers.SerializerMethodField()
used_space_mb = serializers.SerializerMethodField()
available_space_mb = serializers.SerializerMethodField()
is_warning = serializers.SerializerMethodField()
is_critical = serializers.SerializerMethodField()
class Meta:
model = StorageQuota
fields = [
'id',
'user',
'total_quota',
'used_space',
'used_percentage',
'available_space',
'total_quota_mb',
'used_space_mb',
'available_space_mb',
'is_warning',
'is_critical',
'created_at',
'updated_at'
]
read_only_fields = ['user', 'used_space', 'created_at', 'updated_at']
def get_used_percentage(self, obj):
"""Процент использования."""
return round(obj.get_used_percentage(), 2)
def get_available_space(self, obj):
"""Доступное пространство."""
return obj.get_available_space()
def get_total_quota_mb(self, obj):
"""Лимит в МБ."""
return round(obj.total_quota / (1024 * 1024), 2)
def get_used_space_mb(self, obj):
"""Использовано в МБ."""
return round(obj.used_space / (1024 * 1024), 2)
def get_available_space_mb(self, obj):
"""Доступно в МБ."""
return round(obj.get_available_space() / (1024 * 1024), 2)
def get_is_warning(self, obj):
"""Предупреждение (80% и выше)."""
return obj.get_used_percentage() >= 80
def get_is_critical(self, obj):
"""Критическое состояние (90% и выше)."""
return obj.get_used_percentage() >= 90
class MaterialAccessSerializer(serializers.ModelSerializer):
"""Сериализатор лога доступа."""
user = UserSerializer(read_only=True)
material = MaterialListSerializer(read_only=True)
class Meta:
model = MaterialAccess
fields = [
'id',
'material',
'user',
'action',
'ip_address',
'created_at'
]
read_only_fields = ['user', 'created_at']