From e8320bce05af7947d8aa9654df2f10ad9d3ebacd Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 21 May 2026 13:17:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20paper=20list=20=E8=BF=94=20abstract=20+?= =?UTF-8?q?=20=E5=8A=A0=20retrieve=20=E7=AB=AF=E7=82=B9=20+=20filterset=20?= =?UTF-8?q?=E6=89=A9=20year=20range=20/=20=E5=A4=9A=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为 zcbot research skill 让出 LLM 友好接口:list 端点带 abstract 省 LLM 逐条 get 的 round-trip;PaperViewSet 加 CustomRetrieveModelMixin 修 GET /api/resm/paper// 原本 404 的 bug;filterset_class 扩 publication_year_gte/lte + has_fulltext_pdf / is_oa / publication_name / first_author / openalex_id;queryset 加 select_related("abstract") 防 N+1。search_fields 不动(仍 title/first_author/first_author_institution)。 Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/resm/filters.py | 26 ++++++++++++++++++++++++++ apps/resm/serializers.py | 13 ++++++++++++- apps/resm/views.py | 9 +++++---- 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 apps/resm/filters.py diff --git a/apps/resm/filters.py b/apps/resm/filters.py new file mode 100644 index 0000000..7eddc2f --- /dev/null +++ b/apps/resm/filters.py @@ -0,0 +1,26 @@ +from django_filters import rest_framework as filters +from .models import Paper + + +class PaperFilterSet(filters.FilterSet): + # 年份范围(LLM 做"近 N 年文献"很常见) + publication_year_gte = filters.NumberFilter(field_name="publication_year", lookup_expr="gte") + publication_year_lte = filters.NumberFilter(field_name="publication_year", lookup_expr="lte") + + class Meta: + model = Paper + fields = [ + # 原有 + "publication_year", + "type", + "fetch_status", + "has_abstract", + "has_fulltext", + "doi", + # 新增 + "has_fulltext_pdf", # 比 has_fulltext 更准:zcbot research skill 的 has_pdf 参数走这个 + "is_oa", # 是否开放获取 + "publication_name", # 期刊精确名 + "first_author", # 作者精确名 + "openalex_id", # OpenAlex 唯一标识(等价 doi) + ] diff --git a/apps/resm/serializers.py b/apps/resm/serializers.py index c5f69f5..73efee7 100644 --- a/apps/resm/serializers.py +++ b/apps/resm/serializers.py @@ -1,7 +1,18 @@ from apps.utils.serializers import CustomModelSerializer +from rest_framework import serializers from .models import Paper + class PaperListSerializer(CustomModelSerializer): + abstract = serializers.SerializerMethodField() + class Meta: model = Paper - fields = '__all__' \ No newline at end of file + fields = '__all__' + + def get_abstract(self, obj) -> str: + # PaperAbstract 是 O2O,related_name="abstract";无行 / has_abstract=False 时返空串 + abs_obj = getattr(obj, "abstract", None) + if abs_obj is None: + return "" + return abs_obj.abstract or "" diff --git a/apps/resm/views.py b/apps/resm/views.py index c61a82b..74462f5 100644 --- a/apps/resm/views.py +++ b/apps/resm/views.py @@ -5,7 +5,9 @@ from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny from .models import Paper, PaperAbstract from .serializers import PaperListSerializer +from .filters import PaperFilterSet from apps.utils.viewsets import CustomGenericViewSet, CustomListModelMixin +from apps.utils.mixins import CustomRetrieveModelMixin import os @@ -31,11 +33,10 @@ paper_pdf_view.cls.swagger_schema = None # Create your views here. -class PaperViewSet(CustomGenericViewSet, CustomListModelMixin): - queryset = Paper.objects.all() +class PaperViewSet(CustomGenericViewSet, CustomListModelMixin, CustomRetrieveModelMixin): + queryset = Paper.objects.select_related("abstract").all() serializer_class = PaperListSerializer - filterset_fields = ["publication_year", "type", "fetch_status", - "has_abstract", "has_fulltext", "doi"] + filterset_class = PaperFilterSet search_fields = ['title', 'first_author', 'first_author_institution'] ordering = ["-publication_date", "-create_time"]