Files
Zhengen 8fbbd2e6b0 feat: 新增Snippet全局内容模型(TeamMember/Testimonial/Partner/NavigationMenu/SiteSettings)
- 新增 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 进度清单
2026-08-07 13:06:22 +08:00

68 lines
2.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
apps.core 全局 Snippet 只读接口。挂载在 /api/v1/custom/core/
(详见 apps/core/urls.py 与 documents/设计方案分析与完善版.md §2.7)。
公开只读数据,限流走 DRF ScopedRateThrottle 的 "public" scope100/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)