【转帖】利用decorator实现Django表单防重复提交

背景:
  我的用例中不可出现重复的记录,如:下订单,用户填好表单然后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都做缓存,当再次进入表单页时,就不会重新生成随机串,导致校验无故失败。。。)



# 
coding:utf-8

try:
from functools import wraps

except ImportError:
from django.utils.functional import wraps # Python 2.4 fallback.

import random
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
else:
randrange = random.randrange

_MAX_CSRF_KEY = 18446744073709551616L # 2 << 63


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, '')
if old_key == '':
from django.http import HttpResponseRedirect
return HttpResponseRedirect('/page_expir')

request.session['%s_submit' % page_key] = ''

return view_func(request, *args, **kwargs)

return _wrapped_view

return decorator






  使用示例:



@anti_resubmit(page_key='your_view')
def your_view(request):
'''若是表单填写页和POST的view不是同一个,則需在两个view上都使用anti_resubmit装饰器'''
pass #您可别跟着pass噢


2010-12-25 01:14 by 码农.KEN from http://www.cnblogs.com/ken-zhang/archive/2010/12/25/1916437.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值