如何让Django simple history历史条目与主模型使用相同序列化规则
结论
完全可以在HistoricalRecordField的to_representation方法中实现该需求,核心逻辑是复用主模型的序列化规则,同时解决历史记录实例没有计算属性的问题。
问题原因分析
你之前的实现直接调用data.values()返回历史表的原生数据库字段,存在两个问题:
- 历史记录实例是simple-history自动生成的
HistoricalMyModel类实例,没有继承主模型的store等计算属性,所以不会返回对应字段 values()会返回历史表的所有字段,包括history_id、history_date等你不需要的内置字段
修改方案
1. 重写HistoricalRecordField
修改字段逻辑,支持传入主序列化器,把每个历史记录的字段值回填到主模型实例后再用主序列化器序列化:
class HistoricalRecordField(serializers.ListField): def __init__(self, serializer_class, **kwargs): # 接收主模型的序列化器类作为入参,保证规则一致 self.serializer_class = serializer_class super().__init__(**kwargs) def to_representation(self, data): serialized_history = [] # 遍历所有历史记录实例 for history_item in data.all(): # 构造主模型实例,回填历史记录的字段值 main_instance = MyModel() for field in MyModel._meta.fields: field_name = field.name if hasattr(history_item, field_name): setattr(main_instance, field_name, getattr(history_item, field_name)) # 复用主序列化器序列化,自动适配字段规则和计算属性 serialized = self.serializer_class(main_instance) # 可选:如果不需要历史条目里嵌套返回history字段,可以手动删除 serialized.data.pop("history", None) serialized_history.append(serialized.data) return serialized_history
2. 调整MySerializer的history字段声明
传入主序列化器类即可,不需要修改其他逻辑:
class MySerializer(serializers.ModelSerializer): store = serializers.DictField(child=serializers.CharField(), read_only=True) # 传入当前序列化器作为历史条目的序列化规则 history = HistoricalRecordField(serializer_class=lambda: MySerializer, read_only=True) class Meta: model = MyModel # 这里定义的字段就是最终返回的所有字段,自动过滤历史内置字段 fields = ["id", "store", "history"]
效果验证
修改后返回的history数组中的每个条目,字段规则和主模型完全一致:
- 自动包含
store等计算属性 - 不会出现
history_id、history_date等历史内置字段 - 后续如果修改主序列化器的
fields配置,历史条目会自动同步,不需要重复修改
内容的提问来源于stack exchange,提问作者cts
相关产品推荐
相关产品推荐

