""" 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)