场景:
在一些重要的数据表,如设备台账表里,我们希望在记录保存时能够先保存一下旧记录内容,以便出现错误修改时能反查,恢复,这就是我们的需求。
首先我们考虑一下,各数据表数据结构各不相同,如果针对每一个数据表做一个备份表太过繁琐,所以我们考虑只用一个TextField
来保存旧记录内容,而把记录的各字段内容生成Json
的形式保存到TextField
中,就可以不用管各数据表的字段有多少,再附上方便检索和引用的表名、记录号、修改时间、操作人员等字段信息,那一个备份表就基本上够了。
我们在recordbackup
这个应用里
# recordbackup.models.py from django.db import models # Create your models here. class RecordBack(models.Model): app = models.CharField(max_length=20, verbose_name='应用', blank=True) model = models.CharField(max_length=20, verbose_name='数据表') rid = models.IntegerField(verbose_name='记录号') content = models.TextField(verbose_name='原记录内容') modified_time = models.DateTimeField(verbose_name='修改时间') user = models.CharField(max_length=20, verbose_name='操作人') class Meta: verbose_name_plural = verbose_name = '记录备份'
创建admin.py
用于后台查看备份数据,只读
# recordbackup/admin.py from django.contrib import admin from .models import * # Register your models here. @admin.register(RecordBack) class RecordBackAdmin(admin.ModelAdmin): list_display = ('app', 'model', 'rid', 'modified_time', 'user', 'list_operate') readonly_fields = ('app', 'model', 'rid', 'content', 'modified_time', 'user') list_filter = ('app', 'model',) def list_operate(self, obj): return '<a href="/admin/%s/%s/%s/"><i class="icon-th-list" title="查看原记录"></i></a>' % (obj.app, obj.model, obj.rid) list_operate.short_description = '操作' list_operate.allow_tags = True
生成相关数据表
./manage.py makemigrations ./manage.py migrate
再创建一个utils.py
用于转换记录为Json
和保存旧记录功能的函数。
# recordbackup/utils.py import json import datetime def toJSON(obj): """ 对对象进行json序列化,以json序列方式保存记录内容 :param obj: 记录对象 :return: 返回json串 """ fields = [] for field in obj._meta.fields: fields.append(field.name) d = {} for attr in fields: if isinstance(getattr(obj, attr),datetime.datetime): d[attr] = getattr(obj, attr).strftime('%Y-%m-%d %H:%M:%S') elif isinstance(getattr(obj, attr),datetime.date): d[attr] = getattr(obj, attr).strftime('%Y-%m-%d') else: d[attr] = getattr(obj, attr) return json.dumps(d) def OldRecordSave(self, request, obj, form, change): """ 保存旧记录的数据 :param self: 修改前的记录对象 :param request: :param obj: 修改后的记录对象 :param form: 表单数据 :param change: 表单数据是否被修改 :return: None """ from .models import RecordBack if change:# 更改的时候 rb = RecordBack() rb.app = self.model._meta.app_label rb.model = self.model.__name__.lower() rb.rid = obj.pk rb.modified_time = datetime.datetime.now() obj_original = self.model.objects.get(pk=obj.pk) if obj_original: rb.content = toJSON(obj_original) rb.user = request.user rb.save() else:# 新增的时候 pass
现在记录备份的功能可以用了,我们在台账数据表PcAdmin
的save_model()
里加了保存旧记录的操作OldRecordSave()
# pc/admin.py from .models import * from recordbackup.utils import OldRecordSave class PcAdmin(admin.ModelAdmin): ...... def save_model(self, request, obj, form, change): OldRecordSave(self, request, obj, form, change) # 保存旧记录的数据到备份表 obj.save()
现在我们可以做一个测试,进入PC的编辑页面,修改一个字段信息,然后保存,我们看看记录备份
表是不是多出一条记录,内容正是PC保存前的内容。
类似的,我们只要在需要保存旧数据的admin中引入from recordbackup.utils import OldRecordSave
,再在save_model()
的obj.save()
前加入OldRecordSave(self, request, obj, form, change)
就可以实现旧记录数据的保存了。