如何基于DRF实现django-simple-history记录的分页REST API端点?
Django-simple-history 结合DRF实现分页历史记录端点
1. 创建历史记录序列化器
django-simple-history会为每个追踪模型自动生成对应的历史模型(例如原模型为Book,历史模型则是Book.history.model),你可以为这些历史模型编写DRF序列化器,支持单个模型或通用适配多模型:
单个模型序列化器
from rest_framework import serializers from .models import Book class BookHistorySerializer(serializers.ModelSerializer): # 自定义字段展示修改人、操作类型 changed_by = serializers.CharField(source='history_user.username', read_only=True, allow_null=True) change_type = serializers.SerializerMethodField() def get_change_type(self, obj): # 将history_type转换为可读文本 return { '+': '创建', '~': '更新', '-': '删除' }.get(obj.history_type, '未知') class Meta: model = Book.history.model fields = ['history_id', 'history_date', 'change_type', 'changed_by', 'name', 'price'] # 指定需要返回的字段
通用序列化器(适配多模型)
如果需要支持多个模型的历史记录序列化,可写一个动态生成序列化器的方法:
from rest_framework import serializers class GenericHistorySerializer(serializers.ModelSerializer): changed_by = serializers.CharField(source='history_user.username', read_only=True, allow_null=True) change_type = serializers.SerializerMethodField() def get_change_type(self, obj): return { '+': '创建', '~': '更新', '-': '删除' }.get(obj.history_type, '未知') class Meta: model = None fields = '__all__' def get_history_serializer(model): """动态生成对应模型的历史序列化器""" class DynamicHistorySerializer(GenericHistorySerializer): class Meta(GenericHistorySerializer.Meta): model = model.history.model return DynamicHistorySerializer
2. 编写分页历史视图
利用DRF的ListAPIView实现分页,由于你已配置全局分页,视图会自动继承该配置:
模型级历史列表视图(对应/history/model)
from rest_framework.generics import ListAPIView from django.apps import apps from rest_framework.exceptions import NotFound from .serializers import get_history_serializer class ModelHistoryListView(ListAPIView): serializer_class = None def get_queryset(self): # 从URL参数获取模型名称,转换为大写首字母格式匹配模型类 model_name = self.kwargs['model_name'].capitalize() try: # 替换your_app_name为实际应用名 model = apps.get_model(app_label='your_app_name', model_name=model_name) except LookupError: raise NotFound(f"模型 {model_name} 不存在") # 按修改时间倒序返回所有历史记录 return model.history.all().order_by('-history_date') def get_serializer_class(self): model_name = self.kwargs['model_name'].capitalize() model = apps.get_model(app_label='your_app_name', model_name=model_name) return get_history_serializer(model)
实例级历史列表视图(对应/history/model/1)
from rest_framework.generics import ListAPIView from django.apps import apps from rest_framework.exceptions import NotFound from .serializers import get_history_serializer class InstanceHistoryListView(ListAPIView): serializer_class = None def get_queryset(self): model_name = self.kwargs['model_name'].capitalize() obj_id = self.kwargs['obj_id'] try: model = apps.get_model(app_label='your_app_name', model_name=model_name) except LookupError: raise NotFound(f"模型 {model_name} 不存在") # 按修改时间倒序返回指定实例的所有历史记录 return model.history.filter(id=obj_id).order_by('-history_date') def get_serializer_class(self): model_name = self.kwargs['model_name'].capitalize() model = apps.get_model(app_label='your_app_name', model_name=model_name) return get_history_serializer(model)
3. 配置URL路由
在应用的urls.py中添加路由映射:
from django.urls import path from .views import ModelHistoryListView, InstanceHistoryListView urlpatterns = [ # 模型级历史记录端点 path('history/<str:model_name>', ModelHistoryListView.as_view(), name='model-history'), # 实例级历史记录端点 path('history/<str:model_name>/<int:obj_id>', InstanceHistoryListView.as_view(), name='instance-history'), ]
关键说明
- 替换代码中的
your_app_name为你的实际Django应用名称 - 若需权限控制,可在视图类中添加
permission_classes = [IsAuthenticated](需导入rest_framework.permissions.IsAuthenticated) - 全局分页配置会自动生效,若需单独调整分页参数,可在视图中重写
pagination_class - 历史模型默认包含
history_id、history_date、history_type、history_user(已配置用户追踪时)及原模型的所有字段
内容的提问来源于stack exchange,提问作者himmip
相关产品推荐
相关产品推荐

