当前,我有以下付款按钮。
<a href="https://localhost/subscribe/?payload_nonce=token123">PAY NOW</a>
当用户单击链接时,这就是幕后发生的事情。
我希望的是,当用户单击浏览器中的刷新按钮时,将跳过步骤1和步骤2。
我们不希望用户重复付款。
但是,仅显示以前的网关成功/失败结果。
这是TemplateView
代码。
class SubscribeView(TemplateView):
template_name = 'subscribe.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(SubscribeView, self).get_context_data(**kwargs)
# Step 1: Get token input from user
#
payload_nonce = self.request.GET.get('payload_nonce')
# Step 2: Payment gateway processes the
# received token, and return success/fail result.
...
...
##############################
# Submit it to payment gateway
##############################
...
...
# Step 3: Display success/fail result to user.
#
context['is_success'] = result.is_success
context['message'] = result.message
return context
我可以知道什么是确保一次执行TemplateView的get_context_data中的代码逻辑的常用技术吗?
答案 0 :(得分:2)
这里的真正问题是you are updating state in an operation that should be idempotent。
正确的解决方案是使用专用视图仅接受可处理步骤1和2和then redirect to your template view的POST请求(这意味着您需要HTML表单而不是链接)。您当然必须将结果(和关联的令牌)存储在某个位置,以便您可以1.避免为同一令牌重复两次付款,并且2.在模板视图的get_context_data
方法中检索与令牌相关的结果。
NB:当然,您也可以在同一视图中处理GET和POST请求,但是TemplateView
可能不是最佳选择(实际上,基于类的视图很少是最佳选择)除非您需要继承-基于函数的视图通常要简单得多)。
答案 1 :(得分:0)
感谢bruno的除臭剂。这是重构代码。
from django.views.generic import TemplateView
from django.views.generic import View
class SubscribeView(View):
def post(self, request):
# Step 1: Get token input from user
#
payload_nonce = self.request.POST.get("payload_nonce")
# Step 2: Payment gateway processes the
# received token, and return success/fail result.
...
...
##############################
# Submit it to payment gateway
##############################
...
...
# Redirect to SubscribeDoneView, for page rendering purpose.
return redirect(reverse('subscribe_done') + query_string)
class SubscribeDoneView(TemplateView):
template_name = 'subscribe_done.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(SubscribeDoneView, self).get_context_data(**kwargs)
# Step 3: Display success/fail result to user.
#
is_success = (self.request.GET.get('is_success') == 'True')
message = self.request.GET.get('message')
context['is_success'] = is_success
if is_success is False and message is not None:
context['message'] = message
return context