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

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. HDU 5976 Detachment 打表找规律

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5976 Detachment Time Limit: 4000/2000 MS (Java/Other ...

  2. BZOJ SCOI2005骑士精神

    裸IDA*,ans从1到15循环来限制搜索深度. #include<cstdio> #include<cstring> #include<algorithm> us ...

  3. Canvas识别相似图片

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. Struts2(二)---将页面表单中的数据提交给Action

    问题:在struts2框架下,如何将表单数据传递给业务控制器Action. struts2中,表单想Action传递参数的方式有两种,并且这两种传参方式都是struts2默认实现的,他们分别是基本属性 ...

  5. SVN 服务器端安装过程

    1.安装软件版本: VisualSVN-Server-2.1.5.msi 右击安装软件,单机“安装” 2.单击[Next] 选择“I accept the terms in the License A ...

  6. 德州扑克AI实现 TexasHoldem Poker

    参考了一下这篇文献,http://cowboyprogramming.com/2007/01/04/programming-poker-ai/ 自己用go实现了一个德州扑克AI,效果还可以. 正常和它 ...

  7. BZOJ-1854 游戏 二分图匹配 (并查集)

    1854: [Scoi2010]游戏 Time Limit: 5 Sec Memory Limit: 162 MB Submit: 3372 Solved: 1244 [Submit][Status] ...

  8. mysql实用教程的数据构造

    create database XSCJ; use XSCJ; create table XS ( 学号 ) primary key not null, 姓名 ) not null, 专业名 ), 性 ...

  9. BZOJ1022 [SHOI2008]小约翰的游戏John

    Description 小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取 的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不 ...

  10. cowboy-高性能简洁的erlang版web框架

    那么Cowboy是什么呢? Cowboy is a small, fast and modular HTTP server written in Erlang. 其定位非常明确: Cowboy aim ...