0

Django-simple-history 在每次保存目标模型时插入新记录。在文档中描述了 F 表达式的问题。我尝试使用覆盖的保存方法来规避这个问题。

   def save(self, *args, **kwargs):
       super().save(*args, **kwargs)
       # some other actions
       self.refresh_from_db()

但似乎,这行不通。post_save调用后直接调用base model的信号super().save()吗?如果是这样,有没有办法解决这个问题,让 F 表达式保持在目标模型更新中?

更新:保存的实例具有使用 F 表达式定义的属性之一,因此在其他一些模块中调用此代码:

   instance.some_attribute = (F('some_attribute') + 15)
   instance.save(update_fields=['some_attribute'])

这会在 django-simple-history 的信号中引发错误post_save,当它尝试插入instance历史表的扩展副本时。我试图在覆盖save方法中刷新实例以摆脱 F 表达式,some_attribute以便加载实际值。从回溯看来,在调用post_save之后super().save(),刷新之前就调用了。它是 Django post_save 覆盖保存的方式吗?如果是这样,有没有办法不更改更新代码(用 F 表达式保留更新)并解决模型保存中的历史插入?

4

2 回答 2

1

django-simple-history为创建历史记录之前和之后提供信号:https ://django-simple-history.readthedocs.io/en/2.7.0/signals.html

我建议在实例保存到历史表之前使用这些更新实例。像这样的东西应该工作:

from django.dispatch import receiver
from simple_history.signals import (
    pre_create_historical_record,
    post_create_historical_record
)

@receiver(pre_create_historical_record)
def pre_create_historical_record_callback(sender, **kwargs):
    instance = kwargs["instance"]
    history_instance = kwargs["history_instance"]
        if isinstance(instance, ModelYouWantToRefresh)
    instance.refresh_from_db()
    history_instance.some_attribute = instance.some_attribute

于 2020-06-12T17:51:49.917 回答
0

根据罗斯机械师的回答,我提出了一个通用的解决方案

@receiver(
    pre_create_historical_record,
    dispatch_uid='simple_history_refresh')
def remove_f_expressions(sender, instance, history_instance, **kwargs):
    f_fields = []
    for field in history_instance._meta.fields:
        if isinstance(getattr(history_instance, field.name), BaseExpression):
            f_fields.append(field.name)
    if f_fields:
        instance.refresh_from_db()
        for fld_name in f_fields:
            setattr(history_instance, fld_name, getattr(instance, fld_name))
于 2020-06-14T06:50:45.770 回答