如何在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
相关产品推荐
相关产品推荐

