Django后台在记录保存时先保存旧记录内容

场景:
在一些重要的数据表,如设备台账表里,我们希望在记录保存时能够先保存一下旧记录内容,以便出现错误修改时能反查,恢复,这就是我们的需求。

首先我们考虑一下,各数据表数据结构各不相同,如果针对每一个数据表做一个备份表太过繁琐,所以我们考虑只用一个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

现在记录备份的功能可以用了,我们在台账数据表PcAdminsave_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)就可以实现旧记录数据的保存了。

发布时间:
2015-09-21 22:14
分类:
标签: