277 lines
10 KiB
Python
277 lines
10 KiB
Python
![]() |
from django.shortcuts import render
|
|||
|
from django.db.models import Q
|
|||
|
from rest_framework import viewsets, status
|
|||
|
from rest_framework.decorators import action
|
|||
|
from rest_framework.response import Response
|
|||
|
from rest_framework.permissions import AllowAny
|
|||
|
from django.utils import timezone
|
|||
|
|
|||
|
from .models import SearchSession, Creator
|
|||
|
from .serializers import (
|
|||
|
SearchSessionSerializer,
|
|||
|
SearchSessionDetailSerializer,
|
|||
|
CreatorSerializer,
|
|||
|
CreatorDetailSerializer
|
|||
|
)
|
|||
|
from .pagination import StandardResultsSetPagination
|
|||
|
|
|||
|
|
|||
|
class ApiResponse:
|
|||
|
"""API统一响应格式"""
|
|||
|
@staticmethod
|
|||
|
def success(data=None, message="操作成功"):
|
|||
|
return Response({
|
|||
|
"code": 200,
|
|||
|
"message": message,
|
|||
|
"data": data
|
|||
|
})
|
|||
|
|
|||
|
@staticmethod
|
|||
|
def error(message="操作失败", code=400, data=None):
|
|||
|
return Response({
|
|||
|
"code": code,
|
|||
|
"message": message,
|
|||
|
"data": data
|
|||
|
}, status=status.HTTP_200_OK) # 始终返回200状态码,错误信息在内容中提供
|
|||
|
|
|||
|
|
|||
|
class SearchSessionViewSet(viewsets.ModelViewSet):
|
|||
|
"""搜索会话视图集"""
|
|||
|
queryset = SearchSession.objects.all()
|
|||
|
serializer_class = SearchSessionSerializer
|
|||
|
permission_classes = [AllowAny]
|
|||
|
pagination_class = StandardResultsSetPagination
|
|||
|
|
|||
|
def get_serializer_class(self):
|
|||
|
if self.action == 'retrieve':
|
|||
|
return SearchSessionDetailSerializer
|
|||
|
return SearchSessionSerializer
|
|||
|
|
|||
|
def list(self, request, *args, **kwargs):
|
|||
|
queryset = self.filter_queryset(self.get_queryset())
|
|||
|
page = self.paginate_queryset(queryset)
|
|||
|
if page is not None:
|
|||
|
serializer = self.get_serializer(page, many=True)
|
|||
|
return self.get_paginated_response(serializer.data)
|
|||
|
serializer = self.get_serializer(queryset, many=True)
|
|||
|
return ApiResponse.success(serializer.data, "获取搜索会话列表成功")
|
|||
|
|
|||
|
def retrieve(self, request, *args, **kwargs):
|
|||
|
instance = self.get_object()
|
|||
|
serializer = self.get_serializer(instance)
|
|||
|
return ApiResponse.success(serializer.data, "获取搜索会话详情成功")
|
|||
|
|
|||
|
def create(self, request, *args, **kwargs):
|
|||
|
serializer = self.get_serializer(data=request.data)
|
|||
|
serializer.is_valid(raise_exception=True)
|
|||
|
self.perform_create(serializer)
|
|||
|
headers = self.get_success_headers(serializer.data)
|
|||
|
return ApiResponse.success(serializer.data, "创建搜索会话成功")
|
|||
|
|
|||
|
def update(self, request, *args, **kwargs):
|
|||
|
partial = kwargs.pop('partial', False)
|
|||
|
instance = self.get_object()
|
|||
|
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
|||
|
serializer.is_valid(raise_exception=True)
|
|||
|
self.perform_update(serializer)
|
|||
|
return ApiResponse.success(serializer.data, "更新搜索会话成功")
|
|||
|
|
|||
|
def destroy(self, request, *args, **kwargs):
|
|||
|
instance = self.get_object()
|
|||
|
self.perform_destroy(instance)
|
|||
|
return ApiResponse.success(None, "删除搜索会话成功")
|
|||
|
|
|||
|
@action(detail=True, methods=['get'])
|
|||
|
def results(self, request, pk=None):
|
|||
|
"""获取指定会话的搜索结果"""
|
|||
|
session = self.get_object()
|
|||
|
creators = session.creators.all()
|
|||
|
page = self.paginate_queryset(creators)
|
|||
|
if page is not None:
|
|||
|
serializer = CreatorSerializer(page, many=True)
|
|||
|
return self.get_paginated_response(serializer.data)
|
|||
|
serializer = CreatorSerializer(creators, many=True)
|
|||
|
return ApiResponse.success(serializer.data, "获取会话创作者列表成功")
|
|||
|
|
|||
|
|
|||
|
class CreatorDiscoveryViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
|
"""创作者发现视图集"""
|
|||
|
queryset = Creator.objects.all()
|
|||
|
serializer_class = CreatorSerializer
|
|||
|
permission_classes = [AllowAny]
|
|||
|
pagination_class = StandardResultsSetPagination
|
|||
|
|
|||
|
def get_serializer_class(self):
|
|||
|
if self.action == 'retrieve':
|
|||
|
return CreatorDetailSerializer
|
|||
|
return CreatorSerializer
|
|||
|
|
|||
|
def list(self, request, *args, **kwargs):
|
|||
|
queryset = self.filter_queryset(self.get_queryset())
|
|||
|
page = self.paginate_queryset(queryset)
|
|||
|
if page is not None:
|
|||
|
serializer = self.get_serializer(page, many=True)
|
|||
|
return self.get_paginated_response(serializer.data)
|
|||
|
serializer = self.get_serializer(queryset, many=True)
|
|||
|
return ApiResponse.success(serializer.data, "获取创作者列表成功")
|
|||
|
|
|||
|
def retrieve(self, request, *args, **kwargs):
|
|||
|
instance = self.get_object()
|
|||
|
serializer = self.get_serializer(instance)
|
|||
|
return ApiResponse.success(serializer.data, "获取创作者详情成功")
|
|||
|
|
|||
|
@action(detail=False, methods=['post'])
|
|||
|
def search(self, request):
|
|||
|
"""搜索创作者"""
|
|||
|
query = request.data.get('query', '')
|
|||
|
category = request.data.get('category', None)
|
|||
|
ecommerce_level = request.data.get('ecommerce_level', None)
|
|||
|
exposure_level = request.data.get('exposure_level', None)
|
|||
|
|
|||
|
# 创建模拟搜索会话
|
|||
|
session = self._create_mock_search_session()
|
|||
|
|
|||
|
# 生成模拟搜索结果
|
|||
|
creators = self._generate_mock_creators(session, query, category, ecommerce_level, exposure_level)
|
|||
|
|
|||
|
# 返回会话详情
|
|||
|
serializer = SearchSessionDetailSerializer(session)
|
|||
|
return ApiResponse.success(serializer.data, "搜索创作者成功")
|
|||
|
|
|||
|
def _create_mock_search_session(self):
|
|||
|
"""创建模拟搜索会话"""
|
|||
|
# 获取当前最大会话编号并加1
|
|||
|
max_session_number = SearchSession.objects.all().order_by('-session_number').first()
|
|||
|
session_number = 1
|
|||
|
if max_session_number:
|
|||
|
session_number = max_session_number.session_number + 1
|
|||
|
|
|||
|
# 创建新会话
|
|||
|
session = SearchSession.objects.create(
|
|||
|
session_number=session_number,
|
|||
|
creator_count=100,
|
|||
|
shoppable_creators=26,
|
|||
|
avg_followers=162.2,
|
|||
|
avg_gmv=534.1,
|
|||
|
avg_video_views=1.9,
|
|||
|
date_created=timezone.now().date() # 将datetime转换为date类型
|
|||
|
)
|
|||
|
return session
|
|||
|
|
|||
|
def _generate_mock_creators(self, session, query, category=None, ecommerce_level=None, exposure_level=None):
|
|||
|
"""生成模拟创作者数据"""
|
|||
|
# 模拟数据 - 这里可以根据实际需求调整
|
|||
|
mock_creators = [
|
|||
|
{
|
|||
|
"name": "Mock Creator 1",
|
|||
|
"category": "Phones & Electronics",
|
|||
|
"ecommerce_level": "L2",
|
|||
|
"exposure_level": "KOC-1",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": True
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 2",
|
|||
|
"category": "Womenswear & Underwear",
|
|||
|
"ecommerce_level": "L3",
|
|||
|
"exposure_level": "KOL-3",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": False
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 3",
|
|||
|
"category": "Sports & Outdoor",
|
|||
|
"ecommerce_level": "L4",
|
|||
|
"exposure_level": "KOC-2",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": True
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 4",
|
|||
|
"category": "Food & Beverage",
|
|||
|
"ecommerce_level": "L1",
|
|||
|
"exposure_level": "KOC-2",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": True
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 5",
|
|||
|
"category": "Health",
|
|||
|
"ecommerce_level": "L5",
|
|||
|
"exposure_level": "KOL-2",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": False
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 6",
|
|||
|
"category": "Kitchenware",
|
|||
|
"ecommerce_level": "New tag",
|
|||
|
"exposure_level": "New tag",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": True
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 7",
|
|||
|
"category": "Furniture",
|
|||
|
"ecommerce_level": "New tag",
|
|||
|
"exposure_level": "New tag",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": False
|
|||
|
},
|
|||
|
{
|
|||
|
"name": "Mock Creator 8",
|
|||
|
"category": "Shoes",
|
|||
|
"ecommerce_level": "New tag",
|
|||
|
"exposure_level": "New tag",
|
|||
|
"followers": 162.2,
|
|||
|
"gmv": 534.1,
|
|||
|
"items_sold": 18.1,
|
|||
|
"avg_video_views": 1.9,
|
|||
|
"has_ecommerce": True
|
|||
|
},
|
|||
|
]
|
|||
|
|
|||
|
# 根据查询条件过滤模拟数据
|
|||
|
filtered_creators = mock_creators
|
|||
|
if category:
|
|||
|
filtered_creators = [c for c in filtered_creators if c['category'] == category]
|
|||
|
if ecommerce_level:
|
|||
|
filtered_creators = [c for c in filtered_creators if c['ecommerce_level'] == ecommerce_level]
|
|||
|
if exposure_level:
|
|||
|
filtered_creators = [c for c in filtered_creators if c['exposure_level'] == exposure_level]
|
|||
|
|
|||
|
# 创建创作者记录
|
|||
|
for creator_data in filtered_creators:
|
|||
|
Creator.objects.create(
|
|||
|
session=session,
|
|||
|
**creator_data
|
|||
|
)
|
|||
|
|
|||
|
# 更新会话统计信息
|
|||
|
session.creator_count = len(filtered_creators)
|
|||
|
session.shoppable_creators = len([c for c in filtered_creators if c['has_ecommerce']])
|
|||
|
session.save()
|
|||
|
|
|||
|
return filtered_creators
|