# Create your views here. import os from rest_framework.decorators import action from rest_framework.response import Response from rest_framework import status, viewsets, serializers from rest_framework.permissions import IsAuthenticated from crud_book.models import CrudBookModel, ReadingProgress from crud_book.serializers import ( CrudBookModelSerializer, CrudBookModelCreateUpdateSerializer, ReadingProgressSerializer ) from dvadmin.utils.viewset import CustomModelViewSet class CrudBookModelViewSet(CustomModelViewSet): """ list:查询 create:新增 update:修改 retrieve:单例 destroy:删除 """ queryset = CrudBookModel.objects.all() serializer_class = CrudBookModelSerializer create_serializer_class = CrudBookModelCreateUpdateSerializer update_serializer_class = CrudBookModelCreateUpdateSerializer @action(detail=True, methods=['get']) def file(self, request, pk=None): """ 获取图书文件信息或直接下载文件 """ try: # 先检查图书是否存在 try: book = self.get_object() except Exception as e: return Response( {'code': 404, 'msg': f'图书不存在: {str(e)}'}, status=status.HTTP_404_NOT_FOUND ) # 检查图书是否有文件 if not book.file: return Response( {'code': 404, 'msg': '该图书没有上传文件'}, status=status.HTTP_404_NOT_FOUND ) # 检查文件是否实际存在于文件系统 if not os.path.exists(book.file.path): return Response( {'code': 404, 'msg': '文件在服务器上不存在'}, status=status.HTTP_404_NOT_FOUND ) # 返回文件URL信息作为标准格式 file_url = request.build_absolute_uri(book.file.url) return Response({ 'code': 2000, 'data': { 'file_url': file_url, 'file_type': book.file_type or 'epub', 'filename': os.path.basename(book.file.name) }, 'msg': '成功' }, status=status.HTTP_200_OK) except Exception as e: return Response( {'code': 500, 'msg': f'服务器错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR ) class ReadingProgressViewSet(viewsets.ModelViewSet): """ 阅读进度管理 """ queryset = ReadingProgress.objects.all() serializer_class = ReadingProgressSerializer permission_classes = [IsAuthenticated] def get_queryset(self): """只返回当前用户的阅读进度""" return ReadingProgress.objects.filter(user=self.request.user) def create(self, request, *args, **kwargs): """创建或更新阅读进度""" # 检查用户是否已认证 if not request.user.is_authenticated: return Response( {'code': 401, 'msg': '用户未登录,无法保存阅读进度'}, status=status.HTTP_401_UNAUTHORIZED ) # 获取序列化器 serializer = self.get_serializer(data=request.data) try: # 验证数据 serializer.is_valid(raise_exception=True) # 尝试查找现有记录 try: book_id = request.data.get('book_id') book = CrudBookModel.objects.get(id=book_id) # 使用update_or_create而不是普通的save,避免重复记录 progress, created = ReadingProgress.objects.get_or_create( user=request.user, book=book ) # 更新字段 progress.location = request.data.get('location', '') progress.progress = request.data.get('progress', 0) progress.creator = request.user # 确保设置creator progress.save() # 返回更新后的序列化数据,包装成前端期望的格式 serializer = self.get_serializer(progress) return Response( {'code': 2000, 'data': serializer.data, 'msg': '成功'}, status=status.HTTP_200_OK ) except CrudBookModel.DoesNotExist: return Response( {'code': 404, 'msg': f'ID为{book_id}的图书不存在'}, status=status.HTTP_404_NOT_FOUND ) except serializers.ValidationError as e: # 返回序列化验证错误 return Response( {'code': 400, 'msg': str(e.detail)}, status=status.HTTP_400_BAD_REQUEST ) except Exception as e: # 记录错误 import logging logger = logging.getLogger(__name__) logger.error(f'保存阅读进度失败: {str(e)}') return Response( {'code': 500, 'msg': f'保存阅读进度失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR ) @action(detail=False, methods=['get']) def by_book(self, request): """根据图书ID获取阅读进度""" book_id = request.query_params.get('book_id') if not book_id: return Response( {'code': 400, 'msg': '缺少book_id参数'}, status=status.HTTP_400_BAD_REQUEST ) try: progress = ReadingProgress.objects.get( user=request.user, book_id=book_id ) serializer = self.get_serializer(progress) return Response( {'code': 2000, 'data': serializer.data, 'msg': '成功'}, status=status.HTTP_200_OK ) except ReadingProgress.DoesNotExist: return Response( {'code': 2000, 'data': {'location': '', 'progress': 0}, 'msg': '未找到阅读进度记录'}, status=status.HTTP_200_OK )