由于多次涉及到了这个东东,又不是很理解机制,决定深入研究下。

what

  django-revision到底啥玩意?readthedocs上只有一句话概括:django-reversion can be used to add a powerful rollback and recovery facility to your admin site

而且只是说明了能干嘛:给admin后台管理提供强大的回滚和恢复功能。

  下面我们来看看,啥叫作强大的回滚和恢复。

首先,新建一个项目: test_revision,过程略。

新增模型: articles,包含以下字段:

 
序号 栏位 说明
1 title 标题
2 content 内容
3 author 作者
4 status 状态
5 create_date 创建日期
6 publish_date 发布日期

并注册到管理后台。因为只需要看后台,所以views/template/forms全部略。只需要写models 和 admin.py 如下:

models.py

from django.db import models

# Create your models here.
class article(models.Model):
title = models.CharField(max_length=128)
content = models.TextField()
author = models.CharField(max_length=32)
status_list=(('draft','draft'),('pending','pending'),('published','published'))
status = models.CharField(max_length=16, choices=status_list)
create_date = models.DateTimeField(auto_now_add=True)
publish_date = models.DateTimeField()

admin.py

from django.contrib import admin
import reversion
from .models import article
# Register your models here.
class articleAdmin(reversion.VersionAdmin):
list_display = ("id", "title", "author", "status","create_date") admin.site.register(article,articleAdmin)

project文件夹结构:

settings.py的installed_app中添加了“reversion",它涉及到的表是reversion_revision/ reversion_version,如下:

再把test_app加入到installed_app中并syncdb一下,过程略,直接runserver,查看效果,如下:

ok,测试下,

1). 回滚操作:

2). 数据恢复操作:

点击"recover deleted articles"(右侧),选择某个时间对应的对象进入详细,要恢复点击保存即可,如下:

awesome and impressive!

How?

原理:

权威解释看这里:http://django-reversion.readthedocs.org/en/latest/how-it-works.html

这里简单总结下:

被注册,标记,子类化的模型,在其被create/update时会在version表里面做相应的记录,记录的内容就是模型的数据序列化后的json表达式。当需要恢复时,将json表达式反序列化出来,填充到表单里面去,让用户自己选择回滚到哪。至于恢复,则是恢复到最后一次操作后的状态。

如何使用:

以下方式都是在Admin.py中进行。

  1. 继承方式,需要继承reversion.VersionAdmin,适用于新开发的app,如下:

import reversion

class YourModelAdmin(reversion.VersionAdmin):

    pass

admin.site.register(YourModel, YourModelAdmin)

  2. patch_admin注册方式,适用于已存在的尚未使用reversion的app,如下:

from reversion.helpers import patch_admin

patch_admin(User)

  对于尚未在admin.py中注册或者继承versionAdmin的模型,如果要实现版本控制有两个选择:

1). 在admin.py中注册或者继承VersionAdmin

2). 使用reversion的api进行控制,

使用reversion.register()进行注册/修饰对应的模型类.

具体参考这里

后记

发现一个有意思的问题,对于一个已经使用了reversion支持的模型:如果非admin后台修改了记录(update/delete),则delete的数据可以还原,update则无记录。实现如下:

views.py

from django.shortcuts import render
from django.views.generic.edit import UpdateView,DeleteView
from .models import article
from django.shortcuts import render_to_response
# Create your views here. class articleDV(DeleteView):
model = article
success_url = "/admin/test_app/article/"
template_name = "article_delete.html" class articleUV(UpdateView):
model = article
success_url = "/admin/test_app/article/"
template_name = "article_update.html"

解决方案:

适用于django-reversion 1.8.4

采用中间件(可以不用在admin里面继承VersionAdmin),在installed_app中加入中间件"reversion.middleware.RevisionMiddleware",同时修改django-reversion的reversion.py文件(windows则在C:\Python27\Lib\site-packages\django_reversion-1.8.4-py2.7.egg\reversion\revisions.py)的171~182行(原码如下):

                       manager.save_revision(
dict(
(obj, callable(data) and data() or data)
for obj, data
in manager_context.items()
),
user = self._user,
comment = self._comment,
meta = self._meta,
ignore_duplicates = self._ignore_duplicates,
db = self._db,
)

  其中, self._user丢失,原因貌似由于多线程(至少有两个线程执行中间件的process_response方法),导致在实际写入数据的时候,self._user还没赋值,虽然逻辑上是先赋值给revision_context_manager._user(middleware.py 33~36行),后执行此段代码。鉴于这点,还需要修改middleware.py(C:\Python27\Lib\site-packages\django_reversion-1.8.4-py2.7.egg\reversion\middleware.py)的类RevisionMiddleware的_close_revision方法,其原码如下:

    def _close_revision(self, request):
"""Closes the revision."""
if request.META.get(REVISION_MIDDLEWARE_FLAG, False):
del request.META[REVISION_MIDDLEWARE_FLAG]
revision_context_manager.end()

  新代码:

middleware.py(24~28)

    def _close_revision(self, request):
"""Closes the revision."""
if request.META.get(REVISION_MIDDLEWARE_FLAG, False):
del request.META[REVISION_MIDDLEWARE_FLAG]
revision_context_manager.end(request=request)

即:将request传入到reversion.py的RevisionContextManager类的end方法。

reversion.py(171~182)

                        manager.save_revision(
dict(
(obj, callable(data) and data() or data)
for obj, data
in manager_context.items()
),
user = self._user or (hasattr(request, "user") and request.user),
comment = self._comment,
meta = self._meta,
ignore_duplicates = self._ignore_duplicates,
db = self._db,
)

即:重写user的赋值逻辑。

reversion.py(162行),函数定义改为:

def end(self,request=None):

即增加一个参数: request

django revision的更多相关文章

  1. Django 2.0.1 官方文档翻译: 文档目录 (Page 1)

    Django documentation contents 翻译完成后会做标记. 文档按照官方提供的内容一页一页的进行翻译,有些内容涉及到其他节的内容,会慢慢补上.所有的翻译内容按自己的理解来写,尽量 ...

  2. django后台导入excel文件

    1.django 如何从后台上传excel中批量解析数据 要从django后台导入的excel中批量解析数据,举一个例子,我们向后抬批量导入svn历史数据数据格式 假设excel表中有4列,每列分别是 ...

  3. Python使用Django创建第一个项目

    一 必要环境安装 1首先确保安装了Python3,在此使用的系统为Ubuntu @ubuntu:~$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32 ...

  4. 异步任务队列Celery在Django中的使用

    前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...

  5. 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...

  6. django server之间通过remote user 相互调用

    首先,场景是这样的:存在两个django web应用,并且两个应用存在一定的联系.某些情况下彼此需要获取对方的数据. 但是我们的应用肯经都会有对应的鉴权机制.不会让人家随随便便就访问的对吧.好比上车要 ...

  7. Mysql事务探索及其在Django中的实践(二)

    继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...

  8. Mysql事务探索及其在Django中的实践(一)

    前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...

  9. 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...

随机推荐

  1. javascript继承(四)—prototype属性介绍

    js里每一个function都有一个prototype属性,而每一个实例都有constructor属性,并且每一个function的prototype都有一个constructor属性,这个属性会指向 ...

  2. JavaScript基础---语言基础(1)

    写在前面: 通过四篇博客把JS基础中的基础整理一下,方便自己查阅,这些内容对于实际项目开发中也许并不会在意,但是作为JS的语言基础,自觉还是应该熟悉.在完成这三篇博客(JavaScript基础---语 ...

  3. AngularJs——grunt神器的使用

    前面我们已经知道了如何安装grunt,本章节给各位道友介绍如何使用 grunt 的插件,grunt是重点在于如何配置使用 Gruntfile.js,官网上也有很多范例. 1,包装函数 module.e ...

  4. linux 查看服务器性能常用命令

    一.top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器   下面详细介绍它的使用方法.top是一个动态显示过程,即可以通过用户按键来 ...

  5. jQuery Mobile学习日记(二)

    首先依HTML5方式加载,DOCTYPE表示格式为HTML5:主要适用于iPhone.Android等,viewport表示适用于移动终端的适中显示,initial-scale缩放比例在1.0~1.3 ...

  6. [团队项目]Scrum 项目1.0 (演说视频)NABCD

    1.确定选题. 应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 截止日期:2016.5.6日晚10点 2.SCRUM 流 ...

  7. 传智168期JavaEE就业班 day01-html

    * HTML * HTML: HyperText Markup Language 超文本标记语言. * HTML是最基础的网页语言. * HTML的代码都是由标签所组成. * HTML的基本格式 &l ...

  8. WPF--调用线程必须为 STA,因为许多 UI 组件都需要(转载)

    自VS2005开始,UI元素在不同线程中访问就受到限制了,当然你也可以解除这种限制 以下提供Framework3.0的解决方案发: public partial class Window1 : Win ...

  9. BRIEF算法

    本文结构 为了看懂ORB特征提取算法,来看了BRIEF算法的原文,并查看了OpenCV中BRIEF的相关实现,来验证论文的解读正确与否. BRIEF论文解读 摘要 用二进制串描述局部特征,好处有二:一 ...

  10. 【bzoj1202】 HNOI2005—狡猾的商人

    http://www.lydsy.com/JudgeOnline/problem.php?id=1202 (题目链接) 题意 给出m段区间和,判断是否存在某段区间与之前读入的区间相矛盾. Soluti ...