如何在Django Admin中展示django-simple-history关联模型的历史记录?
需求实现:在Product Admin历史页同时展示自身及关联Price的变更记录
我用django-simple-history维护Product和Price模型的历史记录,Price与Product是一对一关联,已经在Admin面板里加了Price内联组件。现在想在Product的Admin历史页面中,同时展示Product自身和关联Price模型的历史变更记录,还要显示对应模型的变更字段。试过通过history_view()和get_history_queryset()获取关联模型的对象,但不知道怎么嵌入渲染来同时呈现两个模型的变更信息,求实现方法。
我的模型代码
class Product(models.Model): article = models.PositiveIntegerField() history = HistoricalRecords() class Price(models.Model): prod = models.OneToOneField( Product,) price_supplier = models.FloatField() history = HistoricalRecords()
我的Admin代码
class PriceInline(admin.TabularInline): model = Price class ProductAdmin(SimpleHistoryAdmin): inlines = [ PriceInline,] admin.site.register(Product, ProductAdmin)
实现方法
1. 重写get_history_queryset获取合并的历史记录
在ProductAdmin中重写该方法,同时拉取Product自身和关联Price的历史记录,再按修改时间倒序合并:
from simple_history.admin import SimpleHistoryAdmin class ProductAdmin(SimpleHistoryAdmin): inlines = [PriceInline,] def get_history_queryset(self, request): # 获取当前Product的历史记录 product_history = super().get_history_queryset(request) # 获取关联Price的历史记录 price_history = self.model.price_set.model.history.filter( prod__id=self.object_id ) # 合并两个查询集并按时间倒序排列 combined_history = product_history.union(price_history).order_by('-history_date') return combined_history
2. 自定义历史页面模板区分模型变更
默认模板只处理当前模型的历史,需要自定义模板来识别不同模型的记录并展示字段变更:
- 在项目
templates/admin/下创建对应路径的模板文件(比如templates/admin/[你的app名]/product/history.html) - 复制Django默认的
object_history.html内容,修改渲染逻辑:
{% extends "admin/object_history.html" %} {% block content %} <div id="content-main"> <p>选择下方日期,可将对象恢复至对应版本。</p> <div class="module"> {% if action_list %} <table id="change-history"> <thead> <tr> <th scope="col">日期/时间</th> <th scope="col">操作人</th> <th scope="col">所属模型</th> <th scope="col">变更说明</th> <th scope="col">变更字段</th> </tr> </thead> <tbody> {% for action in action_list %} <tr> <th scope="row"><a href="{{ action.get_admin_url }}">{{ action.history_date|date:"DATETIME_FORMAT" }}</a></th> <td>{{ action.history_user.get_username|default:action.history_user }}</td> <td> {% if action.model_name == 'product' %} 产品(Product) {% elif action.model_name == 'price' %} 价格(Price) {% endif %} </td> <td>{{ action.get_change_message }}</td> <td> {% if action.changes %} {% for field, values in action.changes.items %} <span>{{ field }}: {{ values.0 }} → {{ values.1 }}</span><br> {% endfor %} {% endif %} </td> </tr> {% endfor %} </tbody> </table> {% else %} <p>该对象暂无变更历史,可能未通过此管理后台添加。</p> {% endif %} </div> </div> {% endblock %}
3. 在Admin中指定自定义模板
修改ProductAdmin,指定历史页面使用刚才创建的模板:
class ProductAdmin(SimpleHistoryAdmin): inlines = [PriceInline,] # 替换为你的实际模板路径 history_template = "admin/[你的app名]/product/history.html" def get_history_queryset(self, request): # 同步骤1的代码 product_history = super().get_history_queryset(request) price_history = self.model.price_set.model.history.filter( prod__id=self.object_id ) combined_history = product_history.union(price_history).order_by('-history_date') return combined_history
关键说明
model_name是django-simple-history为历史记录对象添加的属性,对应原模型的小写名称changes属性返回变更字段的旧值与新值,格式为{字段名: [旧值, 新值]}- 用
union合并查询集可避免重复记录,按history_date倒序能让最新变更排在最前
内容的提问来源于stack exchange,提问作者Анастасия Швечкова
相关产品推荐
相关产品推荐

