如何在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
相关产品推荐
相关产品推荐

