from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from django.core.files.storage import default_storage from django.conf import settings from PIL import Image import os from .models import Project, Asset from .serializers import ProjectSerializer, ProjectDetailSerializer, AssetSerializer @api_view(['GET', 'POST']) def project_list(request): """获取项目列表或创建新项目""" if request.method == 'GET': projects = Project.objects.all() serializer = ProjectSerializer(projects, many=True) return Response(serializer.data) elif request.method == 'POST': # 自动补默认 design/card_overrides/number_layout data = dict(request.data or {}) if 'design' not in data: data['design'] = Project._meta.get_field('design').default() if 'card_overrides' not in data: data['card_overrides'] = Project._meta.get_field('card_overrides').default() if 'number_layout' not in data: data['number_layout'] = Project._meta.get_field('number_layout').default() serializer = ProjectSerializer(data=data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @api_view(['GET', 'PUT', 'DELETE']) def project_detail(request, pk): """获取、更新或删除项目""" try: project = Project.objects.get(pk=pk) except Project.DoesNotExist: return Response({'error': 'Project not found'}, status=status.HTTP_404_NOT_FOUND) if request.method == 'GET': serializer = ProjectDetailSerializer(project) return Response(serializer.data) elif request.method == 'PUT': serializer = ProjectSerializer(project, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) elif request.method == 'DELETE': project.delete() return Response(status=status.HTTP_204_NO_CONTENT) @api_view(['POST']) def project_save_design(request, pk): """整体保存项目设计(design / card_overrides / number_layout)""" try: project = Project.objects.get(pk=pk) except Project.DoesNotExist: return Response({'error': 'Project not found'}, status=status.HTTP_404_NOT_FOUND) for field in ('design', 'card_overrides', 'number_layout', 'face_orientations'): if field in request.data: setattr(project, field, request.data[field]) project.save() return Response({ 'ok': True, 'design': project.design, 'card_overrides': project.card_overrides, 'number_layout': project.number_layout, 'face_orientations': project.face_orientations, }) @api_view(['GET', 'POST']) def asset_list(request, project_pk): """获取项目素材列表或上传新素材""" try: project = Project.objects.get(pk=project_pk) except Project.DoesNotExist: return Response({'error': 'Project not found'}, status=status.HTTP_404_NOT_FOUND) if request.method == 'GET': assets = project.assets.all() serializer = AssetSerializer(assets, many=True, context={'request': request}) return Response(serializer.data) elif request.method == 'POST': if 'file' not in request.FILES: return Response({'error': 'No file provided'}, status=status.HTTP_400_BAD_REQUEST) file = request.FILES['file'] asset_type = request.POST.get('asset_type', 'unknown') asset_key = request.POST.get('asset_key', 'unknown') # 创建项目素材目录 project_media_dir = os.path.join('projects', str(project.id), asset_type) full_dir = os.path.join(settings.MEDIA_ROOT, project_media_dir) os.makedirs(full_dir, exist_ok=True) # 避免重名覆盖:补上时间戳 from time import time ts = int(time() * 1000) file_name = f"{asset_key}_{ts}_{file.name}" file_path = os.path.join(project_media_dir, file_name) saved_path = default_storage.save(file_path, file) # 获取图片尺寸 width, height = None, None try: img = Image.open(file) width, height = img.size except Exception: pass asset = Asset.objects.create( project=project, asset_type=asset_type, asset_key=asset_key, file_path=saved_path, file_name=file_name, width=width, height=height, ) serializer = AssetSerializer(asset, context={'request': request}) return Response(serializer.data, status=status.HTTP_201_CREATED) @api_view(['GET', 'DELETE']) def asset_detail(request, project_pk, asset_pk): """获取或删除单个素材""" try: project = Project.objects.get(pk=project_pk) asset = project.assets.get(pk=asset_pk) except (Project.DoesNotExist, Asset.DoesNotExist): return Response({'error': 'Asset not found'}, status=status.HTTP_404_NOT_FOUND) if request.method == 'GET': serializer = AssetSerializer(asset, context={'request': request}) return Response(serializer.data) elif request.method == 'DELETE': if asset.file_path: file_full_path = os.path.join(settings.MEDIA_ROOT, asset.file_path) if os.path.exists(file_full_path): try: os.remove(file_full_path) except OSError: pass asset.delete() return Response(status=status.HTTP_204_NO_CONTENT)