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

如何在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,提问作者Анастасия Швечкова

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:12:21