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

如何从django-simple-history获取_history_user_id并生成HTML表格?

解决django-simple-history历史修改用户字段的访问问题

问题背景

使用django-simple-history的simple_history.middleware.HistoryRequestMiddleware追踪模型修改用户,UI显示正常,但生成修改记录HTML报告时,获取到的是模型本身的user字段ID,而非历史表中记录修改操作的history_user_id。尝试添加_history_user属性未解决,需获取历史表的history_user_id关联的用户信息并整合到报告中。

原模型代码

class Degree(TimeStampedModel):
    user = ForeignKey(User, null=True, blank=True, related_name='degrees', on_delete=CASCADE)
    level = CharField(max_length=50, null=True, blank=True, choices=LEVELS)
    institution = CharField(max_length=255, null=True)
    major = CharField(max_length=255, null=True, blank=True)
    minor = CharField(max_length=255, null=True, blank=True)
    verified_date = DateField(null=True, blank=True)
    graduation_date = DateField(null=True, blank=True)
    reason_for_change = CharField(max_length=255, null=True)
    history = HistoricalRecords(User)

原报告视图代码

def Changelog_table(request):
    name = 'Changelog'
    desc = 'changelog'
    headers = [
        ('', ''),
        ('user__last_name', 'Last name'),
        ('user__first_name', 'First name'),
        ('reason_for_change', 'Reason for change'),
        ('section', 'section'),
        ('modified', 'modified'),
        ('user', 'user')
    ]
    filters = {
        'user__is_active': True,
    }
    values = [
        'user__username',
        'user__last_name',
        'user__first_name',
        'reason_for_change',
        'section',
        'modified',
        'user',
        ]
    qs_degree = (
        Degree.objects.filter(**filters) \
            .values_list(*values)
    )

    return render(request, 'reports/report.html', {
        'headers': headers,
        'data': json.dumps(list(qs_degree), cls=DjangoJSONEncoder),
        'name': name,
        'desc': desc,
    })

尝试过的无效修改(添加_history_user属性)

class Degree(TimeStampedModel):
    user = ForeignKey(User, null=True, blank=True, related_name='degrees', on_delete=CASCADE)
    level = CharField(max_length=50, null=True, blank=True, choices=LEVELS)
    institution = CharField(max_length=255, null=True)
    major = CharField(max_length=255, null=True, blank=True)
    minor = CharField(max_length=255, null=True, blank=True)
    verified_date = DateField(null=True, blank=True)
    graduation_date = DateField(null=True, blank=True)
    reason_for_change = CharField(max_length=255, null=True)
    history = HistoricalRecords(User)

    @property
    def _history_user(self):
        return self.user

解决方案

核心问题是原代码查询的是Degree主表,而所有修改记录(包括修改者信息)存储在django-simple-history自动生成的HistoricalDegree历史表中。需调整查询逻辑到历史表,并正确关联history_user字段。

步骤1:修正模型定义

移除HistoricalRecords的User参数,删除无用的_history_user属性。HistoryRequestMiddleware会自动从请求中获取当前用户并绑定到历史记录的history_user字段:

class Degree(TimeStampedModel):
    user = ForeignKey(User, null=True, blank=True, related_name='degrees', on_delete=CASCADE)
    level = CharField(max_length=50, null=True, blank=True, choices=LEVELS)
    institution = CharField(max_length=255, null=True)
    major = CharField(max_length=255, null=True, blank=True)
    minor = CharField(max_length=255, null=True, blank=True)
    verified_date = DateField(null=True, blank=True)
    graduation_date = DateField(null=True, blank=True)
    reason_for_change = CharField(max_length=255, null=True)
    history = HistoricalRecords()  # 无需传入User参数

步骤2:修改报告视图,查询历史表

将查询对象切换到HistoricalDegree,并添加历史用户的关联字段:

def Changelog_table(request):
    name = 'Changelog'
    desc = 'changelog'
    # 调整表头,区分原数据用户和修改操作用户
    headers = [
        ('', ''),
        ('user__last_name', '原用户姓氏'),
        ('user__first_name', '原用户名字'),
        ('history_user__last_name', '修改者姓氏'),
        ('history_user__first_name', '修改者名字'),
        ('reason_for_change', '修改原因'),
        ('history_date', '修改时间'),
        ('history_type', '操作类型'),
    ]
    # 可选:过滤历史记录类型,只保留新增/修改记录
    filters = {
        'history_type__in': ['+', '~'],  # +=新增,~=修改,-=删除
    }
    # 指定需要查询的字段,包含历史用户的信息
    values = [
        'user__username',
        'user__last_name',
        'user__first_name',
        'history_user__username',
        'history_user__last_name',
        'history_user__first_name',
        'reason_for_change',
        'history_date',
        'history_type',
    ]
    # 查询历史表,按修改时间倒序排列
    qs_degree_history = (
        HistoricalDegree.objects.filter(**filters)
        .order_by('-history_date')
        .values_list(*values)
    )

    return render(request, 'reports/report.html', {
        'headers': headers,
        'data': json.dumps(list(qs_degree_history), cls=DjangoJSONEncoder),
        'name': name,
        'desc': desc,
    })

关键说明

  • HistoricalDegree是django-simple-history自动生成的历史模型,命名规则为Historical+原模型名
  • 通过history_user__xxx可以访问历史表中history_user_id关联的用户信息
  • history_date记录修改操作的时间,history_type记录操作类型(新增/修改/删除)

内容的提问来源于stack exchange,提问作者Invisible

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:18:32