You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django REST Framework的ModelViewSet中通过@action记录带筛选条件的GET请求?

如何在Django REST Framework的ModelViewSet中通过@action记录带筛选条件的GET请求?

咱们先理清楚你的核心需求:要记录所有带?event_report__id=<id>这个查询参数的列表请求,而不是新开一个接口来做这件事对吧?你现在用自定义@action的方式虽然能拿到过滤结果,但其实有点绕远路——相当于额外加了一个新接口端点,既会漏掉对默认列表接口的日志记录,还会让前端对接时需要记住额外的请求路径,不太符合RESTful的设计习惯。

给你两种更贴合DRF设计风格的方案,都是不用额外加action的:

方案一:直接重写ModelViewSet的list方法

ModelViewSet自带的list方法就是专门处理GET列表请求的,咱们直接在这个方法里插入日志逻辑就行,完全复用DRF自带的过滤、序列化、响应逻辑,不用自己重复造轮子。

代码示例:

from rest_framework import viewsets
from .models import EventReportLink
from .serializers import EventReportLinkSerializer
import logging

logger = logging.getLogger(__name__)

class EventReportLinkViewSet(viewsets.ModelViewSet):
    queryset = EventReportLink.objects.all()
    serializer_class = EventReportLinkSerializer
    # 如果用了django-filter做过滤,这里正常配置过滤字段就行
    # filterset_fields = ['event_report__id']

    def list(self, request, *args, **kwargs):
        # 先检查查询参数里有没有目标id
        event_report_id = request.query_params.get('event_report__id')
        if event_report_id:
            # 可以根据需求扩展日志内容,比如加上请求用户、时间等信息
            logger.info(f"用户查询了event_report__id为{event_report_id}的EventReportLink数据")
        
        # 调用父类的list方法,保留所有默认逻辑(过滤、序列化、返回响应)
        return super().list(request, *args, **kwargs)

这个方案的优势很明显:

  • 完全遵循RESTful规范,用户还是用原来的GET请求地址(比如/event-report-links/?event_report__id=123),不需要修改请求路径
  • 不用自己处理filter_queryset、序列化这些细节,DRF会自动帮你搞定
  • 所有带该查询参数的列表请求都会被记录,不会有遗漏

方案二:用装饰器实现日志逻辑复用

如果你的多个ViewSet都需要记录类似的查询参数日志,把日志逻辑抽成装饰器会更方便复用,不用每个ViewSet都写一遍相同的代码。

先写一个通用的装饰器:

import logging

logger = logging.getLogger(__name__)

def log_event_report_query(view_func):
    def wrapper(self, request, *args, **kwargs):
        event_report_id = request.query_params.get('event_report__id')
        if event_report_id:
            logger.info(f"用户查询event_report__id: {event_report_id}")
        return view_func(self, request, *args, **kwargs)
    return wrapper

然后在ViewSet的list方法上应用这个装饰器:

class EventReportLinkViewSet(viewsets.ModelViewSet):
    queryset = EventReportLink.objects.all()
    serializer_class = EventReportLinkSerializer

    @log_event_report_query
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

这样其他ViewSet需要相同日志逻辑时,直接加这个装饰器就好,代码更简洁易维护。

为什么不推荐你原来的@action方式?

你原来的做法相当于新建了一个/log-test端点,只有请求这个端点时才会触发日志,但用户正常的列表查询(请求默认的列表接口)不会被记录,这显然不符合你“记录每次有人用?event_report__id=<id>查询”的需求。而且额外加端点会让你的接口变得不统一,增加前端对接的成本。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 14:33:09