背景:
我的用例中不可出现重复的记录,如:下订单,用户填好表单然后Submit,当用户网速较慢时,很可能会习惯性的刷新当前页,而刷新操作会导致再次POST,此时若不加判断直接入库必然导致用户后台增加N个订单。
解决思路:
Step 1:首先我们在进入表单填写页面时,对该页面(或view吧)随机生成一个校验字符串并存放于Session中,在页面form中新增一个hidden input来存放,以便提交时一起POST到服务器端;
Step
2:当POST时,服务器端将收到的校验串与Session中对应值比对,若相同则正常提交,否则跳转至指定的错误提示页面;需要注意的是当比对成功后,
必须立即将该Session的值设置为空,这样才可保证页面再次POST时表单中的校验串就无法于Session中的空值比对成功。
实现:
为了方便使用,我们将上述思路写成一个decorator(装饰器). 当然也是为了符合DRY嘛;代码很简单就看中间那几行,需注意唯一的一个参数page_key,为了不跟多个表单页面发生Session key冲突。(补充一点:必须将表单填写页面的view同时使用@never_cache装饰,因为django默认将所有view都做缓存,当再次进入表单页时,就不会重新生成随机串,导致校验无故失败。。。
)
from
functools
import
wraps
|
from
django.utils.functional
import
wraps
|
from
django.conf
import
settings
|
from
django.utils.decorators
import
available_attrs
|
from
django.utils.hashcompat
import
md5_constructor
|
if
hasattr
(random,
'SystemRandom'
):
|
randrange
=
random.SystemRandom().randrange
|
randrange
=
random.randrange
|
_MAX_CSRF_KEY
=
18446744073709551616L
|
def
_get_new_submit_key():
|
return
md5_constructor(
"%s%s"
%
(randrange(
0
, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
|
def
anti_resubmit(page_key
=
''):
|
def
decorator(view_func):
|
@wraps
(view_func, assigned
=
available_attrs(view_func))
|
def
_wrapped_view(request,
*
args,
*
*
kwargs):
|
if
request.method
=
=
'GET'
:
|
request.session[
'%s_submit'
%
page_key]
=
_get_new_submit_key()
|
print
'session:'
+
request.session.get(
'%s_submit'
%
page_key)
|
elif
request.method
=
=
'POST'
:
|
old_key
=
request.session.get(
'%s_submit'
%
page_key, '')
|
from
django.http
import
HttpResponseRedirect
|
return
HttpResponseRedirect(
'/page_expir'
)
|
request.session[
'%s_submit'
%
page_key]
=
''
|
return
view_func(request,
*
args,
*
*
kwargs)
|
使用示例:
1
@anti_resubmit(page_key
=
'
your_view
'
)
2
def
your_view(request):
3
'''
若是表单填写页和POST的view不是同一个,則需在两个view上都使用anti_resubmit装饰器
'''
4
pass
#
您可别跟着pass噢
分享到:
相关推荐
奇幻RPG(物品锻造 与 Decorator模式)本文中,我们通过一个常见的给武器(对象)添加宝石(额外的状态和行为)的例子,讨论了Decorator设计模式的实现过程。
eventbus-cjs 是一个基于JavaScript装饰器(Decorator)实现的通信库, 支持Vue / React等常用框架, 支持node.js
Ajax-django-ajax.zip,django应用程序的快速而简单的ajax库。包含ajax decorator、ajax中间件、快捷方式等。,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于...
decorator-wechat,微信现代化(Nevolution decorator).zip
最近做了一个系统由于部分...Django Ratelimit is a ratelimiting decorator for Django views. http://huoche.7234.cn/images/jb51/anzpeymerkt.png?branch=master Code: https://github.com/jsocol/django-ratelimit
博文链接:https://your.iteye.com/blog/133420
软件介绍: 这个decorator python是网友分享过来的一个模块文件,既然下载肯定会知道它的用途。
*Decorator 常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这两种实体在Decorator 模式中是必须的。
学习java 装饰模式(decorator)非常好的例子
23种设计模式之八(结构型模式)Decorator模式
decorator-4.1.2.tar.gz是支持ipython的依赖包。。。。
windows系统下的python超时装饰器,解决pypi中timeout-decorator库在windows系统上不可用的问题。
Decorator-3.4.0.tar.gz, a python package
最近学习了plover的底层框架koa,所以下面这篇文章主要给大家介绍了关于利用Decorator如何控制Koa路由的相关资料,,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来随着小编一起学习学习吧
Head First 设计模式 (三) 装饰者模式(decorator pattern) C++实现 VS2012 下通过
Decorator常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee。这两种实体在Decorator模式中是必须的。 Decorator定义:动态给一个对象添加...
扩展方面:可以在 routes/decorator.ts中,实现类似Java swagger自动生成API文档的能力 安装 npm cd backend npm install 定义基类Controller @Controller({ prefix: '/api' }) class ApiController extends Base...
demo python使用装饰器(Decorator)的方式实现单例模式 functools.wraps 则可以将原函数对象的指定属性复制给包装函数对象, 默认有 __module__、__name__、__doc__,或者通过参数选择
1、Decorator 自定义边框 2、Adorner调整控件大小和位置