feat: ADRF async views (phase1) + native async serializers (phase2) + async cache infra
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
from django.http import JsonResponse
|
||||
from rest_framework.views import APIView
|
||||
from adrf.views import APIView
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||
from django.db.models import Count, Q
|
||||
@@ -19,8 +19,8 @@ class ToolCategoryListView(APIView):
|
||||
tags=['工具'],
|
||||
responses={200: success_response}
|
||||
)
|
||||
def get(self, request):
|
||||
categories = ToolCategory.objects.prefetch_related('tools').all()
|
||||
async def get(self, request):
|
||||
categories = [c async for c in ToolCategory.objects.prefetch_related('tools').all()]
|
||||
serializer = ToolCategorySerializer(categories, many=True)
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
@@ -42,7 +42,7 @@ class ToolListView(APIView):
|
||||
],
|
||||
responses={200: success_response}
|
||||
)
|
||||
def get(self, request):
|
||||
async def get(self, request):
|
||||
category_id = request.query_params.get('category_id')
|
||||
enabled_only = request.query_params.get('enabled_only', 'true')
|
||||
ordering = request.query_params.get('ordering', '')
|
||||
@@ -68,18 +68,19 @@ class ToolListView(APIView):
|
||||
else:
|
||||
tools = tools.order_by('sort_order', '-created_at')
|
||||
|
||||
serializer = ToolSerializer(tools, many=True)
|
||||
tool_list = [t async for t in tools]
|
||||
serializer = ToolSerializer(tool_list, many=True)
|
||||
data = serializer.data
|
||||
|
||||
# 构建 favorites_count 映射
|
||||
favorites_count_map = {
|
||||
t.id: t.annotated_favorites_count for t in tools
|
||||
t.id: t.annotated_favorites_count for t in tool_list
|
||||
}
|
||||
|
||||
if request.user.is_authenticated:
|
||||
favorite_tool_ids = set(
|
||||
ToolFavorite.objects.filter(user=request.user).values_list('tool_id', flat=True)
|
||||
)
|
||||
favorite_tool_ids = set([
|
||||
tid async for tid in ToolFavorite.objects.filter(user=request.user).values_list('tool_id', flat=True)
|
||||
])
|
||||
for item in data:
|
||||
item['is_favorited'] = item['id'] in favorite_tool_ids
|
||||
item['favorites_count'] = favorites_count_map.get(item['id'], 0)
|
||||
@@ -106,18 +107,18 @@ class ToolDetailView(APIView):
|
||||
],
|
||||
responses={200: success_response, 404: not_found_response}
|
||||
)
|
||||
def get(self, request, pk):
|
||||
async def get(self, request, pk):
|
||||
try:
|
||||
tool = Tool.objects.select_related('category').get(pk=pk, is_enabled=True)
|
||||
tool = await Tool.objects.select_related('category').aget(pk=pk, is_enabled=True)
|
||||
serializer = ToolSerializer(tool)
|
||||
data = serializer.data
|
||||
if request.user.is_authenticated:
|
||||
data['is_favorited'] = ToolFavorite.objects.filter(
|
||||
data['is_favorited'] = await ToolFavorite.objects.filter(
|
||||
user=request.user, tool=tool
|
||||
).exists()
|
||||
).aexists()
|
||||
else:
|
||||
data['is_favorited'] = False
|
||||
data['favorites_count'] = ToolFavorite.objects.filter(tool=tool).count()
|
||||
data['favorites_count'] = await ToolFavorite.objects.filter(tool=tool).acount()
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'data': data
|
||||
@@ -141,20 +142,20 @@ class ToolFavoriteToggleView(APIView):
|
||||
],
|
||||
responses={200: success_response, 401: unauthorized_response, 404: not_found_response}
|
||||
)
|
||||
def post(self, request, pk):
|
||||
tool = Tool.objects.filter(pk=pk, is_enabled=True).first()
|
||||
async def post(self, request, pk):
|
||||
tool = await Tool.objects.filter(pk=pk, is_enabled=True).afirst()
|
||||
if not tool:
|
||||
return JsonResponse(
|
||||
{'success': False, 'error': '工具不存在'},
|
||||
status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
fav, created = ToolFavorite.objects.get_or_create(user=request.user, tool=tool)
|
||||
fav, created = await ToolFavorite.objects.aget_or_create(user=request.user, tool=tool)
|
||||
if not created:
|
||||
fav.delete()
|
||||
await fav.adelete()
|
||||
is_favorited = False
|
||||
else:
|
||||
is_favorited = True
|
||||
favorites_count = ToolFavorite.objects.filter(tool=tool).count()
|
||||
favorites_count = await ToolFavorite.objects.filter(tool=tool).acount()
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'data': {
|
||||
@@ -174,17 +175,19 @@ class ToolFavoriteListView(APIView):
|
||||
tags=['工具'],
|
||||
responses={200: success_response, 401: unauthorized_response}
|
||||
)
|
||||
def get(self, request):
|
||||
favorites = ToolFavorite.objects.select_related('tool', 'tool__category').filter(
|
||||
async def get(self, request):
|
||||
favorites = [fav async for fav in ToolFavorite.objects.select_related(
|
||||
'tool', 'tool__category'
|
||||
).filter(
|
||||
user=request.user,
|
||||
tool__is_enabled=True
|
||||
).order_by('-created_at')
|
||||
).order_by('-created_at')]
|
||||
|
||||
result = []
|
||||
for fav in favorites:
|
||||
tool_data = ToolSerializer(fav.tool).data
|
||||
tool_data['is_favorited'] = True
|
||||
tool_data['favorites_count'] = ToolFavorite.objects.filter(tool=fav.tool).count()
|
||||
tool_data['favorites_count'] = await ToolFavorite.objects.filter(tool=fav.tool).acount()
|
||||
result.append(tool_data)
|
||||
|
||||
return JsonResponse({
|
||||
@@ -206,13 +209,13 @@ class ToolUsageIncrementView(APIView):
|
||||
],
|
||||
responses={200: success_response, 404: not_found_response}
|
||||
)
|
||||
def post(self, request, pk):
|
||||
async def post(self, request, pk):
|
||||
try:
|
||||
tool = Tool.objects.get(pk=pk, is_enabled=True)
|
||||
tool = await Tool.objects.aget(pk=pk, is_enabled=True)
|
||||
# 使用F()表达式避免竞态条件
|
||||
from django.db.models import F
|
||||
Tool.objects.filter(pk=pk).update(usage_count=F('usage_count') + 1)
|
||||
tool.refresh_from_db()
|
||||
await Tool.objects.filter(pk=pk).aupdate(usage_count=F('usage_count') + 1)
|
||||
await tool.arefresh_from_db()
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'data': {
|
||||
|
||||
Reference in New Issue
Block a user