Django技术问题:如何将RecordObject存入RecordHistory表且不创建新对象?
自动记录RecordObject的更新到RecordHistory(无需手动创建历史对象)
看起来你应该是想避免在每次更新RecordObject时都手动写代码创建RecordHistory实例,而不是完全不创建新的历史记录(毕竟要存更新历史,每条更新对应一条新的历史条目才合理对吧?)。如果是这样的话,Django的信号系统刚好能解决这个问题,它可以自动帮你完成历史记录的保存,不用在业务逻辑里重复写代码。
第一步:完善模型(可选但非常推荐)
首先建议给RecordHistory加个外键关联到RecordObject,这样能明确每条历史属于哪个主记录,再加个自动记录历史创建时间的字段,方便追踪更新时机:
from django.db import models class RecordObject(models.Model): # 记得给CharField指定max_length,不然Django会报错 status = models.CharField(max_length=50) # 如果collection_date是日期类型,用DateField会比CharField更合适哦 collection_date = models.CharField(max_length=20) class RecordHistory(models.Model): # 关联到对应的RecordObject,删除主记录时自动删除对应的历史 record = models.ForeignKey(RecordObject, on_delete=models.CASCADE, related_name='histories') status = models.CharField(max_length=50) collection_date = models.CharField(max_length=20) # 自动记录这条历史的创建时间 updated_at = models.DateTimeField(auto_now_add=True)
第二步:用Django信号自动触发历史记录保存
在你的app目录下新建一个signals.py文件(如果已经有就直接用),然后写信号处理函数:
from django.db.models.signals import post_save from django.dispatch import receiver from .models import RecordObject, RecordHistory @receiver(post_save, sender=RecordObject) def save_record_history(sender, instance, created, **kwargs): # 如果是新建的RecordObject,我们不需要记录历史(如果需要新建也记录,把这个判断删掉就行) if not created: # 这里保存的是更新后的状态,如果要保存更新前的状态,看下面的补充 RecordHistory.objects.create( record=instance, status=instance.status, collection_date=instance.collection_date )
然后要在app的apps.py里注册这个信号,不然Django找不到它:
from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'your_app_name' # 替换成你的app实际名称 def ready(self): # 导入信号模块 import your_app_name.signals # 同样替换成你的app名称
补充:如果要记录更新前的旧状态
上面的代码是保存更新后的状态,要是你想存更新前的旧数据,就得先用pre_save信号缓存旧实例的数据,再在post_save里用:
from django.db.models.signals import pre_save, post_save from django.dispatch import receiver from .models import RecordObject, RecordHistory # 用个临时字典存旧数据,同一个请求周期里pre_save和post_save能共享这个数据 old_record_cache = {} @receiver(pre_save, sender=RecordObject) def cache_old_record(sender, instance, **kwargs): # 只有已存在的对象更新时才缓存旧数据 if instance.pk: old_instance = sender.objects.get(pk=instance.pk) old_record_cache[instance.pk] = { 'status': old_instance.status, 'collection_date': old_instance.collection_date } @receiver(post_save, sender=RecordObject) def save_old_record_history(sender, instance, created, **kwargs): if not created: # 取出缓存的旧数据,然后删掉缓存避免占用内存 old_data = old_record_cache.pop(instance.pk, None) if old_data: RecordHistory.objects.create( record=instance, status=old_data['status'], collection_date=old_data['collection_date'] )
这样一来,以后你每次更新RecordObject并保存时,系统都会自动帮你创建对应的RecordHistory记录,完全不用在业务代码里手动写创建历史对象的代码——这应该就是你说的“不创建新的RecordHistory对象的前提下”的真实需求啦。
内容的提问来源于stack exchange,提问作者nischal
相关产品推荐
相关产品推荐

