页面加载时加载时间戳并与表单提交时的时间戳进行比较
我在我的应用程序中开发了一个反垃圾邮件的时间限制措施(我知道这并不是百分之百有效,但至少可以暂时解决问题),它的工作原理是这样的:
1) 当页面加载时,使用JavaScript在一个隐藏的输入框中填入一个时间戳:
var timestamp = new Date().getTime() / 1000;
2) 当表单提交时,使用Python的视图来检查这个时间戳和当前时间的差异——如果从页面加载到现在还不到5秒,就会抛出一个异常:
import datetime
feedback_timestamp = request.POST['feedback_timestamp'].strip()
current_timestamp = datetime.datetime.now().timestamp()
if current_timestamp - float(feedback_timestamp) < 5:
raise Exception("Submitted too quickly after loading!")
在我本地的开发服务器上,这个方法运行得很好(也就是说,它强制你等待5秒,否则就会抛出异常)。但是,我注意到一旦在我的生产服务器上加载,时间戳之间的差异大约有30秒,即使我在加载页面后立刻提交表单。看起来JavaScript函数获取的是本地用户的时间,而Python代码获取的是服务器的时间,所以如果两者不同步,就无法正常触发。
我的问题是:我该如何从服务器获取初始时间戳,而不是从本地机器获取?有没有什么JavaScript函数可以做到这一点?还是说我需要通过Python后端来填充这个隐藏的输入框呢?
如果是后者,那事情就有点复杂,因为这一切都是在我的base.html中完成的,而这个文件并不是由我的任何视图直接加载的(也就是说,它是用来扩展我使用的许多其他视图的)。我该如何在不使用与页面关联的视图的情况下,从Python后端获取一个值呢?
2 个回答
你可以使用一个上下文处理器来给每个模板添加一个时间戳的上下文变量。上下文处理器其实就是一个简单的Python函数,它接收一个HttpRequest
参数,然后返回一个字典,这个字典会被添加到你的上下文字典中。
你的函数可能看起来像这样:
def timestamp(request):
ctx = {
'timestamp': timezone.now()
}
return ctx
接着,在你的settings.py
文件中,把你的函数添加到TEMPLATE_CONTEXT_PROCESSORS
里:
TEMPLATE_CONTEXT_PROCESSORS = (
...,
'path.to.function.context_processors.timestamp',
)
就这样! 你可以在这里查看更详细的文档。
如果你不想在视图中处理逻辑,可以通过上下文处理器把变量发送到模板中:
def add_timestamp_context(request):
return {'current_time': datetime.datetime.now()}
或者类似的东西。想了解更多细节,可以查看这里。你需要在你的settings.py
文件中,把这个新函数添加到TEMPLATE_CONTEXT_PROCESSORS
变量里,文档中有说明。
另外要注意,所有发送到模板的变量都会在你的base.html
中可用。所以你可以从相关的视图把变量发送到模板,这样即使前端逻辑在base.html
文件中也能正常工作。
在我看来,最好的解决方案是把两个时间戳的计算放在前端,而不是后端。