feat: ADRF async views (phase1) + native async serializers (phase2) + async cache infra

This commit is contained in:
async-upgrade
2026-09-06 14:26:17 +08:00
parent 9a6577f71e
commit 8f488fcaaa
55 changed files with 2224 additions and 1513 deletions
+19 -15
View File
@@ -1,6 +1,7 @@
from rest_framework import status
from rest_framework.views import APIView
from adrf.views import APIView
from rest_framework.permissions import IsAuthenticated
from asgiref.sync import sync_to_async
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import logging
@@ -38,12 +39,12 @@ class SendChangeEmailCodeAPIView(APIView):
),
responses={200: success_response, 400: error_response, 401: unauthorized_response, 500: error_response},
)
def post(self, request):
async def post(self, request):
from utils.captcha import check_captcha_required, verify_captcha, record_failure, reset_failures
identifier = str(request.user.id)
operation = 'change_email'
captcha_required = check_captcha_required(operation, identifier)
captcha_required = await sync_to_async(check_captcha_required)(operation, identifier)
if captcha_required:
captcha_key = request.data.get('captcha_key', None)
@@ -55,14 +56,14 @@ class SendChangeEmailCodeAPIView(APIView):
status_code=status.HTTP_400_BAD_REQUEST
)
captcha_result = verify_captcha(captcha_key, captcha_code)
captcha_result = await sync_to_async(verify_captcha)(captcha_key, captcha_code)
if captcha_result == 'expired':
return create_standardized_error_response(
code=ResponseCode.CAPTCHA_EXPIRED,
status_code=status.HTTP_400_BAD_REQUEST
)
elif captcha_result == 'wrong':
record_failure(operation, identifier)
await sync_to_async(record_failure)(operation, identifier)
return create_standardized_error_response(
code=ResponseCode.CAPTCHA_ERROR,
status_code=status.HTTP_400_BAD_REQUEST
@@ -73,7 +74,8 @@ class SendChangeEmailCodeAPIView(APIView):
context={'request': request}
)
if not serializer.is_valid():
# 校验器内含同步 ORM(validate_email 查重)与 cache 写入,线程池兜底
if not await sync_to_async(serializer.is_valid)():
errors = serializer.errors
first_error = ''
for field, msgs in errors.items():
@@ -81,7 +83,7 @@ class SendChangeEmailCodeAPIView(APIView):
first_error = str(msgs[0])
break
record_failure(operation, identifier)
await sync_to_async(record_failure)(operation, identifier)
return create_standardized_error_response(
data=errors,
code=ResponseCode.PARAMETER_ERROR,
@@ -90,24 +92,25 @@ class SendChangeEmailCodeAPIView(APIView):
)
email = serializer.validated_data.get('email')
if email and not validate_email_mx(email):
if email and not await sync_to_async(validate_email_mx)(email):
logger.warning(f'[ChangeEmail] Domain MX check failed: email={email}')
record_failure(operation, identifier)
await sync_to_async(record_failure)(operation, identifier)
return create_standardized_error_response(
code=ResponseCode.EMAIL_DOMAIN_INVALID,
status_code=status.HTTP_400_BAD_REQUEST
)
try:
email = serializer.save()
reset_failures(operation, identifier)
# save() 内部触发验证码邮件发送(Celery/cache/SMTP 链路),线程池兜底
email = await sync_to_async(serializer.save)()
await sync_to_async(reset_failures)(operation, identifier)
return create_standardized_response(
data={'email_sent': True},
code=ResponseCode.EMAIL_CHANGE_CODE_SENT,
status_code=status.HTTP_200_OK
)
except Exception as e:
record_failure(operation, identifier)
await sync_to_async(record_failure)(operation, identifier)
return create_standardized_error_response(
message=f'邮件发送失败: {str(e)}',
code=ResponseCode.EMAIL_SEND_FAILED,
@@ -131,13 +134,14 @@ class ChangeEmailAPIView(APIView):
),
responses={200: success_response, 400: error_response, 401: unauthorized_response, 500: error_response},
)
def post(self, request):
async def post(self, request):
serializer = ChangeEmailSerializer(
data=request.data,
context={'request': request}
)
if not serializer.is_valid():
# 校验器内含同步 ORM 查询,线程池兜底
if not await sync_to_async(serializer.is_valid)():
errors = serializer.errors
first_error = ''
for field, msgs in errors.items():
@@ -153,7 +157,7 @@ class ChangeEmailAPIView(APIView):
)
try:
updated_user = serializer.save()
updated_user = await sync_to_async(serializer.save)()
user_serializer = UserSerializer(updated_user)
return create_standardized_response(