什么是通用技术,以确保一次执行TemplateView的get_context_data中的代码逻辑?

时间:2018-08-28 10:01:57

标签: python django

当前,我有以下付款按钮。

<a href="https://localhost/subscribe/?payload_nonce=token123">PAY NOW</a>

当用户单击链接时,这就是幕后发生的事情。

  1. 获取用户的令牌输入。
  2. 付款网关处理收到的令牌,并返回成功/失败结果。
  3. 向用户显示成功/失败结果。

我希望的是,当用户单击浏览器中的刷新按钮时,将跳过步骤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中的代码逻辑的常用技术吗?

2 个答案:

答案 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