feat: ADRF async views (phase1) + native async serializers (phase2) + async cache infra
This commit is contained in:
+43
-39
@@ -1,40 +1,44 @@
|
||||
from rest_framework import serializers
|
||||
from adrf.serializers import (
|
||||
ModelSerializer, CharField, ImageField, DateTimeField,
|
||||
ListField, FileField, SerializerMethodField,
|
||||
)
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from .models import (
|
||||
BugReport, BugReportImage, BugReportAttachment,
|
||||
BugReportComment, BugReportCommentImage, BugReportCommentAttachment
|
||||
)
|
||||
|
||||
|
||||
class BugReportImageSerializer(serializers.ModelSerializer):
|
||||
class BugReportImageSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = BugReportImage
|
||||
fields = ['id', 'image', 'created_at']
|
||||
|
||||
|
||||
class BugReportAttachmentSerializer(serializers.ModelSerializer):
|
||||
class BugReportAttachmentSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = BugReportAttachment
|
||||
fields = ['id', 'file', 'filename', 'file_size', 'created_at']
|
||||
|
||||
|
||||
class BugReportCommentImageSerializer(serializers.ModelSerializer):
|
||||
class BugReportCommentImageSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = BugReportCommentImage
|
||||
fields = ['id', 'image', 'created_at']
|
||||
|
||||
|
||||
class BugReportCommentAttachmentSerializer(serializers.ModelSerializer):
|
||||
class BugReportCommentAttachmentSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = BugReportCommentAttachment
|
||||
fields = ['id', 'file', 'filename', 'file_size', 'created_at']
|
||||
|
||||
|
||||
class BugReportCommentSerializer(serializers.ModelSerializer):
|
||||
user_name = serializers.CharField(source='user.nickname', read_only=True)
|
||||
user_avatar = serializers.ImageField(source='user.avatar', read_only=True)
|
||||
class BugReportCommentSerializer(ModelSerializer):
|
||||
user_name = CharField(source='user.nickname', read_only=True)
|
||||
user_avatar = ImageField(source='user.avatar', read_only=True)
|
||||
images = BugReportCommentImageSerializer(many=True, read_only=True)
|
||||
attachments = BugReportCommentAttachmentSerializer(many=True, read_only=True)
|
||||
created_at = serializers.DateTimeField(format='%Y-%m-%d %H:%M')
|
||||
created_at = DateTimeField(format='%Y-%m-%d %H:%M')
|
||||
|
||||
class Meta:
|
||||
model = BugReportComment
|
||||
@@ -45,9 +49,9 @@ class BugReportCommentSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ['user', 'is_admin']
|
||||
|
||||
|
||||
class BugReportListSerializer(serializers.ModelSerializer):
|
||||
user_name = serializers.CharField(source='user.nickname', read_only=True)
|
||||
images_count = serializers.SerializerMethodField()
|
||||
class BugReportListSerializer(ModelSerializer):
|
||||
user_name = CharField(source='user.nickname', read_only=True)
|
||||
images_count = SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = BugReport
|
||||
@@ -56,13 +60,13 @@ class BugReportListSerializer(serializers.ModelSerializer):
|
||||
'created_at', 'updated_at', 'user_name', 'images_count'
|
||||
]
|
||||
|
||||
def get_images_count(self, obj):
|
||||
return obj.images.count()
|
||||
async def get_images_count(self, obj):
|
||||
return await obj.images.acount()
|
||||
|
||||
|
||||
class BugReportDetailSerializer(serializers.ModelSerializer):
|
||||
user_name = serializers.CharField(source='user.nickname', read_only=True)
|
||||
user_avatar = serializers.ImageField(source='user.avatar', read_only=True)
|
||||
class BugReportDetailSerializer(ModelSerializer):
|
||||
user_name = CharField(source='user.nickname', read_only=True)
|
||||
user_avatar = ImageField(source='user.avatar', read_only=True)
|
||||
images = BugReportImageSerializer(many=True, read_only=True)
|
||||
attachments = BugReportAttachmentSerializer(many=True, read_only=True)
|
||||
comments = BugReportCommentSerializer(many=True, read_only=True)
|
||||
@@ -78,14 +82,14 @@ class BugReportDetailSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ['user', 'status']
|
||||
|
||||
|
||||
class BugReportCreateSerializer(serializers.ModelSerializer):
|
||||
images = serializers.ListField(
|
||||
child=serializers.ImageField(),
|
||||
class BugReportCreateSerializer(ModelSerializer):
|
||||
images = ListField(
|
||||
child=ImageField(),
|
||||
required=False,
|
||||
max_length=5
|
||||
)
|
||||
attachments = serializers.ListField(
|
||||
child=serializers.FileField(),
|
||||
attachments = ListField(
|
||||
child=FileField(),
|
||||
required=False,
|
||||
max_length=3
|
||||
)
|
||||
@@ -98,27 +102,27 @@ class BugReportCreateSerializer(serializers.ModelSerializer):
|
||||
max_size = 10 * 1024 * 1024 # 10MB
|
||||
for image in value:
|
||||
if image.size > max_size:
|
||||
raise serializers.ValidationError(f"图片 {image.name} 大小超过10MB限制")
|
||||
raise ValidationError(f"图片 {image.name} 大小超过10MB限制")
|
||||
return value
|
||||
|
||||
def validate_attachments(self, value):
|
||||
max_size = 20 * 1024 * 1024 # 20MB
|
||||
for attachment in value:
|
||||
if attachment.size > max_size:
|
||||
raise serializers.ValidationError(f"附件 {attachment.name} 大小超过20MB限制")
|
||||
raise ValidationError(f"附件 {attachment.name} 大小超过20MB限制")
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
async def acreate(self, validated_data):
|
||||
images_data = validated_data.pop('images', [])
|
||||
attachments_data = validated_data.pop('attachments', [])
|
||||
|
||||
bug_report = BugReport.objects.create(**validated_data)
|
||||
bug_report = await BugReport.objects.acreate(**validated_data)
|
||||
|
||||
for image in images_data:
|
||||
BugReportImage.objects.create(bug_report=bug_report, image=image)
|
||||
await BugReportImage.objects.acreate(bug_report=bug_report, image=image)
|
||||
|
||||
for attachment in attachments_data:
|
||||
BugReportAttachment.objects.create(
|
||||
await BugReportAttachment.objects.acreate(
|
||||
bug_report=bug_report,
|
||||
file=attachment,
|
||||
filename=attachment.name,
|
||||
@@ -128,14 +132,14 @@ class BugReportCreateSerializer(serializers.ModelSerializer):
|
||||
return bug_report
|
||||
|
||||
|
||||
class BugReportCommentCreateSerializer(serializers.ModelSerializer):
|
||||
images = serializers.ListField(
|
||||
child=serializers.ImageField(),
|
||||
class BugReportCommentCreateSerializer(ModelSerializer):
|
||||
images = ListField(
|
||||
child=ImageField(),
|
||||
required=False,
|
||||
max_length=3
|
||||
)
|
||||
attachments = serializers.ListField(
|
||||
child=serializers.FileField(),
|
||||
attachments = ListField(
|
||||
child=FileField(),
|
||||
required=False,
|
||||
max_length=2
|
||||
)
|
||||
@@ -148,27 +152,27 @@ class BugReportCommentCreateSerializer(serializers.ModelSerializer):
|
||||
max_size = 10 * 1024 * 1024 # 10MB
|
||||
for image in value:
|
||||
if image.size > max_size:
|
||||
raise serializers.ValidationError(f"图片 {image.name} 大小超过10MB限制")
|
||||
raise ValidationError(f"图片 {image.name} 大小超过10MB限制")
|
||||
return value
|
||||
|
||||
def validate_attachments(self, value):
|
||||
max_size = 20 * 1024 * 1024 # 20MB
|
||||
for attachment in value:
|
||||
if attachment.size > max_size:
|
||||
raise serializers.ValidationError(f"附件 {attachment.name} 大小超过20MB限制")
|
||||
raise ValidationError(f"附件 {attachment.name} 大小超过20MB限制")
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
async def acreate(self, validated_data):
|
||||
images_data = validated_data.pop('images', [])
|
||||
attachments_data = validated_data.pop('attachments', [])
|
||||
|
||||
comment = BugReportComment.objects.create(**validated_data)
|
||||
comment = await BugReportComment.objects.acreate(**validated_data)
|
||||
|
||||
for image in images_data:
|
||||
BugReportCommentImage.objects.create(comment=comment, image=image)
|
||||
await BugReportCommentImage.objects.acreate(comment=comment, image=image)
|
||||
|
||||
for attachment in attachments_data:
|
||||
BugReportCommentAttachment.objects.create(
|
||||
await BugReportCommentAttachment.objects.acreate(
|
||||
comment=comment,
|
||||
file=attachment,
|
||||
filename=attachment.name,
|
||||
|
||||
+33
-16
@@ -1,10 +1,14 @@
|
||||
from rest_framework import generics, permissions, status
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
|
||||
from asgiref.sync import sync_to_async
|
||||
from django.utils import timezone
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_yasg import openapi
|
||||
from chunyu_project.common_schemas import success_response, error_response, unauthorized_response, not_found_response
|
||||
|
||||
from adrf import generics
|
||||
|
||||
from .models import BugReport, BugReportComment
|
||||
from .serializers import (
|
||||
BugReportListSerializer,
|
||||
@@ -35,12 +39,15 @@ class BugReportListCreateAPIView(generics.ListCreateAPIView):
|
||||
operation_description='获取当前用户提交的所有Bug反馈列表',
|
||||
responses={200: success_response, 401: unauthorized_response}
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
async def list(self, request, *args, **kwargs):
|
||||
queryset = self.get_queryset()
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
items = [x async for x in queryset]
|
||||
serializer = self.get_serializer(items, many=True)
|
||||
# 兜底:user_name 触发 user 外键懒加载、images_count 内部有同步 ORM count()
|
||||
data = await sync_to_async(lambda: serializer.data)()
|
||||
return create_standardized_response(
|
||||
code=ResponseCode.SUCCESS,
|
||||
data=serializer.data,
|
||||
data=data,
|
||||
message='获取Bug反馈列表成功'
|
||||
)
|
||||
|
||||
@@ -51,14 +58,18 @@ class BugReportListCreateAPIView(generics.ListCreateAPIView):
|
||||
request_body=BugReportCreateSerializer,
|
||||
responses={201: success_response, 400: error_response, 401: unauthorized_response}
|
||||
)
|
||||
def create(self, request, *args, **kwargs):
|
||||
async def create(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
bug_report = serializer.save(user=request.user)
|
||||
is_valid = await sync_to_async(serializer.is_valid)()
|
||||
if is_valid:
|
||||
# 兜底:serializer.create 内部有同步 ORM(BugReport/BugReportImage/BugReportAttachment 的 create)
|
||||
bug_report = await sync_to_async(serializer.save)(user=request.user)
|
||||
detail_serializer = BugReportDetailSerializer(bug_report)
|
||||
# 兜底:detail 序列化会触发 user/images/attachments/comments 的同步懒加载
|
||||
data = await sync_to_async(lambda: detail_serializer.data)()
|
||||
return create_standardized_response(
|
||||
code=ResponseCode.SUCCESS,
|
||||
data=detail_serializer.data,
|
||||
data=data,
|
||||
message='Bug反馈提交成功',
|
||||
status_code=status.HTTP_201_CREATED
|
||||
)
|
||||
@@ -88,13 +99,15 @@ class BugReportDetailAPIView(generics.RetrieveAPIView):
|
||||
],
|
||||
responses={200: success_response, 401: unauthorized_response, 404: not_found_response}
|
||||
)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
async def retrieve(self, request, *args, **kwargs):
|
||||
try:
|
||||
instance = self.get_object()
|
||||
instance = await self.get_object()
|
||||
serializer = self.get_serializer(instance)
|
||||
# 兜底:detail 序列化会触发 user/images/attachments/comments 的同步懒加载
|
||||
data = await sync_to_async(lambda: serializer.data)()
|
||||
return create_standardized_response(
|
||||
code=ResponseCode.SUCCESS,
|
||||
data=serializer.data,
|
||||
data=data,
|
||||
message='获取Bug反馈详情成功'
|
||||
)
|
||||
except BugReport.DoesNotExist:
|
||||
@@ -119,10 +132,10 @@ class BugReportCommentCreateAPIView(generics.CreateAPIView):
|
||||
request_body=BugReportCommentCreateSerializer,
|
||||
responses={201: success_response, 400: error_response, 401: unauthorized_response, 404: not_found_response}
|
||||
)
|
||||
def create(self, request, *args, **kwargs):
|
||||
async def create(self, request, *args, **kwargs):
|
||||
bug_report_id = kwargs.get('bug_report_id')
|
||||
try:
|
||||
bug_report = BugReport.objects.get(id=bug_report_id, user=request.user)
|
||||
bug_report = await BugReport.objects.aget(id=bug_report_id, user=request.user)
|
||||
except BugReport.DoesNotExist:
|
||||
return create_standardized_error_response(
|
||||
code=ResponseCode.NOT_FOUND,
|
||||
@@ -131,16 +144,20 @@ class BugReportCommentCreateAPIView(generics.CreateAPIView):
|
||||
)
|
||||
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
comment = serializer.save(
|
||||
is_valid = await sync_to_async(serializer.is_valid)()
|
||||
if is_valid:
|
||||
# 兜底:serializer.create 内部有同步 ORM(comment 及其图片/附件的 create)
|
||||
comment = await sync_to_async(serializer.save)(
|
||||
user=request.user,
|
||||
bug_report=bug_report,
|
||||
is_admin=False
|
||||
)
|
||||
comment_serializer = BugReportCommentSerializer(comment)
|
||||
# 兜底:comment 序列化会触发 user 外键与 images/attachments 的同步懒加载
|
||||
data = await sync_to_async(lambda: comment_serializer.data)()
|
||||
return create_standardized_response(
|
||||
code=ResponseCode.SUCCESS,
|
||||
data=comment_serializer.data,
|
||||
data=data,
|
||||
message='回复成功',
|
||||
status_code=status.HTTP_201_CREATED
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user