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

如何在Python通用日志函数中获取外键的名称而非ID或对象格式?

问题描述

现有如下Django模型:

class User(models.Model):
    id = models.AutoField(...)
    group = models.ForeignKey(
        Group,
        ...
    )
    ...

class Group(models.Model):
    id = models.AutoField(...)
    name = models.CharField(...)
    ...

在变更触发的自定义日志函数中,编写了以下代码:

obj = # 被更新的对象/模型;此处为User实例
old_values = {}
new_values = {}
for i in range(len(form.changed_data)):
    vname = obj._meta.get_field(form.changed_data[i]).verbose_name

    old_values.update(
        { vname: form[form.changed_data[i]].initial }
    )
    new_values.update(
        { vname: form.cleaned_data[form.changed_data[i]] }
    )

运行后得到的输出不符合预期:

old_values = {'Group': 2}

new_values = {'Group': <Group: New Group Name>}

期望输出为:

old_values = {'Group': 'Old Group Name'}

new_values = {'Group': 'New Group Name'}

限制条件:不能显式导入模型类,该日志函数需要统一处理数十个类似模型,User和Group只是其中两个。此前尝试过apps.get_model()、get_object_or_404()等方法未成功。

解决方案

可以通过Django模型字段的元数据和对象的__str__方法统一处理,无需显式导入模型:

修改日志函数代码如下:

from django.db import models

obj = # 被更新的对象/模型;此处为User实例
old_values = {}
new_values = {}
for field_name in form.changed_data:
    # 获取字段实例及verbose_name
    field = obj._meta.get_field(field_name)
    vname = field.verbose_name

    # 处理旧值:外键字段通过ID获取对应对象的友好名称
    old_val = form[field_name].initial
    if isinstance(field, models.ForeignKey):
        related_model = field.remote_field.model
        if old_val:
            # 通过主键获取关联对象
            old_obj = related_model.objects.get(pk=old_val)
            # 优先用模型__str__返回的友好名称,或直接取name字段
            old_val = str(old_obj)
        else:
            old_val = ""

    # 处理新值:外键实例直接转友好名称
    new_val = form.cleaned_data[field_name]
    if isinstance(new_val, models.Model):
        new_val = str(new_val)
    elif isinstance(field, models.ForeignKey) and new_val is None:
        new_val = ""

    old_values[vname] = old_val
    new_values[vname] = new_val

核心逻辑说明:

  • 自动识别外键:通过isinstance(field, models.ForeignKey)判断字段类型,无需硬编码模型名称。
  • 动态获取关联模型:利用字段的remote_field.model属性直接获取外键关联的模型类,完全适配任意模型。
  • 通用名称取值:依赖模型的__str__方法返回友好名称,只要所有模型的__str__都按需求实现(比如Group的__str__返回self.name),就能统一输出规范的名称。如果不想依赖__str__,也可以替换为old_obj.name这种明确字段取值,但通用性会稍弱。
  • 空值兼容:添加空值判断,避免空外键场景下出现异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 22:25:11