- 新增 apps.core.TeamMember/Testimonial/Partner:简单 register_snippet,含 order 排序字段
- 新增 apps.core.NavigationMenu+NavigationMenuItem:ClusterableModel+Orderable+InlinePanel,
支持内部页面或外部链接二选一
- 新增 apps.core.SiteSettings:接入 wagtail.contrib.settings + BaseSiteSetting,
存放公司信息/ICP备案号/社交账号等全局配置
- 新增只读 API:/api/v1/custom/core/{team,testimonials,partners,navigation,site-settings}/
- 补充 apps/core/tests.py 单元测试,pytest 用例由 11 个增至 24 个,全部通过
- 更新设计文档 §2.16 Phase 1 进度清单
68 lines
2.3 KiB
Python
68 lines
2.3 KiB
Python
"""
|
||
apps.core 全局 Snippet 只读接口。挂载在 /api/v1/custom/core/
|
||
(详见 apps/core/urls.py 与 documents/设计方案分析与完善版.md §2.7)。
|
||
公开只读数据,限流走 DRF ScopedRateThrottle 的 "public" scope(100/min)。
|
||
"""
|
||
from rest_framework.response import Response
|
||
from rest_framework.throttling import ScopedRateThrottle
|
||
from rest_framework.views import APIView
|
||
|
||
from .models import NavigationMenu, Partner, SiteSettings, TeamMember, Testimonial
|
||
from .serializers import (
|
||
NavigationMenuSerializer,
|
||
PartnerSerializer,
|
||
SiteSettingsSerializer,
|
||
TeamMemberSerializer,
|
||
TestimonialSerializer,
|
||
)
|
||
|
||
|
||
class TeamMemberListView(APIView):
|
||
throttle_classes = [ScopedRateThrottle]
|
||
throttle_scope = "public"
|
||
|
||
def get(self, request, *args, **kwargs):
|
||
members = TeamMember.objects.all()
|
||
return Response({"items": TeamMemberSerializer(members, many=True).data})
|
||
|
||
|
||
class TestimonialListView(APIView):
|
||
throttle_classes = [ScopedRateThrottle]
|
||
throttle_scope = "public"
|
||
|
||
def get(self, request, *args, **kwargs):
|
||
testimonials = Testimonial.objects.all()
|
||
return Response({"items": TestimonialSerializer(testimonials, many=True).data})
|
||
|
||
|
||
class PartnerListView(APIView):
|
||
throttle_classes = [ScopedRateThrottle]
|
||
throttle_scope = "public"
|
||
|
||
def get(self, request, *args, **kwargs):
|
||
partners = Partner.objects.all()
|
||
return Response({"items": PartnerSerializer(partners, many=True).data})
|
||
|
||
|
||
class NavigationMenuView(APIView):
|
||
"""根据 ?name= 查询指定导航菜单(如 main / footer)。"""
|
||
|
||
throttle_classes = [ScopedRateThrottle]
|
||
throttle_scope = "public"
|
||
|
||
def get(self, request, *args, **kwargs):
|
||
name = request.query_params.get("name", "main")
|
||
menu = NavigationMenu.objects.prefetch_related("items").filter(name=name).first()
|
||
if menu is None:
|
||
return Response({"error": {"code": "NOT_FOUND", "message": "导航菜单不存在"}}, status=404)
|
||
return Response(NavigationMenuSerializer(menu).data)
|
||
|
||
|
||
class SiteSettingsView(APIView):
|
||
throttle_classes = [ScopedRateThrottle]
|
||
throttle_scope = "public"
|
||
|
||
def get(self, request, *args, **kwargs):
|
||
settings_obj = SiteSettings.for_request(request)
|
||
return Response(SiteSettingsSerializer(settings_obj).data)
|