【问题标题】:How to fix "TypeError at /orders/create/ argument of type 'DeferredAttribute' is not iterable" when using Django Payment Gateway (Paytm)使用 Django 支付网关 (Paytm) 时如何修复“'DeferredAttribute' 类型的 /orders/create/ 参数的 TypeError 不可迭代”
【发布时间】:2019-05-17 11:52:49
【问题描述】:

我的问题是在我的电子商务项目中实施支付网关。我使用的支付网关是来自印度国家的“Paytm”。

访问他们的网站后,https://developer.paytm.com/docs/v1/payment-gateway

我收集了我的测试 ID 和密钥。

我有一个结帐页面,一旦用户输入他/她的详细信息。他被重定向到带有订单 ID 的成功下单页面。 一切正常。

但是,现在当我开始实施支付网关时,我在订单应用程序的 views.py 文件中遇到错误“'DeferredAttribute' 类型的参数不可迭代”。

首先我用 pip3 安装了 pycryptodome

我在我的 src 文件夹下创建了一个名为“payTm”的目录。我制作了一个名为“Checksum.py”的新python文件。(我从paytm的网站复制粘贴)

所以我的问题出现在我的views.py文件下。

views.py(在订单应用中)

 from django.shortcuts import render
 from .models import OrderItem , Order
 from django.contrib.auth.decorators import login_required
 from django.views.decorators.csrf import csrf_exempt
 from .forms import OrderCreateForm
 from cart.cart import Cart
 from payTm import Checksum
 from django.http import HttpResponse
 MERCHANT_KEY = 'my_merchant_key';

 @csrf_exempt
 def handlerequest(request):
 return HttpResponse('done')
 pass

 @login_required
 def order_create(request):
 cart = Cart(request)
 if request.method == 'POST':
    form = OrderCreateForm(request.POST)
    if form.is_valid():
        order = form.save()
        for item in cart:
            OrderItem.objects.create(
                order=order,
                product=item['product'],
                price=item['price'],
                quantity=item['quantity'],
                total_price=item['total_price'],
            )
        cart.clear()
        param_dict = {
            'MID': 'my_merchant_id',
            'ORDER_ID': str(Order.id),
            'TXN_AMOUNT': Order.total_cost,
            'CUST_ID': Order.email,
            'INDUSTRY_TYPE_ID': 'Retail',
            'WEBSITE': 'WENSTAGING',
            'CHANNEL_ID': 'WEB',
            'CALLBACK_URL': 'http://127.0.0.1:8000/handlerequest',
        }
        param_dict['CHECKSUMHASH'] = 
        Checksum.generate_checksum(param_dict, MERCHANT_KEY)
        return render(request, 'paytm.html', {'order': order}, 
        {'param_dict': param_dict})

 else:
    form = OrderCreateForm()
   return render(request, 'create.html', {'form': form})

服务器运行没有任何错误。

但是错误输出是:

Error

这是我的 html 页面。 帖子 URL 链接由 paytm 本身从他们的网站提供。 paytm.html

{% extends 'base.html %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Paytm merchant Payment Page</title>
</head>
<body>
<h1> Redirecting you to the merchant.....</h1>
<h1> Please don't refresh this page.....</h1>
<form action="https://securegw-stage.paytm.in/theia/processTransaction"  
method="post" name="paytm">
{% for key,value in param_dict.items %}
<input type="hidden" name="{{ key }}" value="{{ value }}">
{% endfor %}
</form>
</body>
<script>
document.paytm.submit()
</script>
</html>

校验和.py

import base64
import string
import random
import hashlib

from Crypto.Cipher import AES


IV = "@@@@&&&&####$$$$"
BLOCK_SIZE = 16


  def generate_checksum(param_dict, merchant_key, salt=None):
 params_string = __get_param_string__(param_dict)
 salt = salt if salt else __id_generator__(4)
 final_string = '%s|%s' % (params_string, salt)

 hasher = hashlib.sha256(final_string.encode())
 hash_string = hasher.hexdigest()

 hash_string += salt

 return __encode__(hash_string, IV, merchant_key)

 def generate_refund_checksum(param_dict, merchant_key, salt=None):
  for i in param_dict:
    if("|" in param_dict[i]):
        param_dict = {}
        exit()
  params_string = __get_param_string__(param_dict)
  salt = salt if salt else __id_generator__(4)
  final_string = '%s|%s' % (params_string, salt)

  hasher = hashlib.sha256(final_string.encode())
  hash_string = hasher.hexdigest()

  hash_string += salt

  return __encode__(hash_string, IV, merchant_key)


 def generate_checksum_by_str(param_str, merchant_key, salt=None):
 params_string = param_str
 salt = salt if salt else __id_generator__(4)
 final_string = '%s|%s' % (params_string, salt)

 hasher = hashlib.sha256(final_string.encode())
 hash_string = hasher.hexdigest()

 hash_string += salt

 return __encode__(hash_string, IV, merchant_key)


 def verify_checksum(param_dict, merchant_key, checksum):
 # Remove checksum
 if 'CHECKSUMHASH' in param_dict:
    param_dict.pop('CHECKSUMHASH')

 # Get salt
 paytm_hash = __decode__(checksum, IV, merchant_key)
 salt = paytm_hash[-4:]
 calculated_checksum = generate_checksum(param_dict, merchant_key, 
 salt=salt)
 return calculated_checksum == checksum

 def verify_checksum_by_str(param_str, merchant_key, checksum):
 # Remove checksum
 #if 'CHECKSUMHASH' in param_dict:
    #param_dict.pop('CHECKSUMHASH')

 # Get salt
 paytm_hash = __decode__(checksum, IV, merchant_key)
 salt = paytm_hash[-4:]
 calculated_checksum = generate_checksum_by_str(param_str, 
  merchant_key, 
 salt=salt)
 return calculated_checksum == checksum



 def __id_generator__(size=6, chars=string.ascii_uppercase +   
 string.digits + string.ascii_lowercase):
 return ''.join(random.choice(chars) for _ in range(size))


 def __get_param_string__(params):
 params_string = []
 for key in sorted(params.keys()):
    if("REFUND" in params[key] or "|" in params[key]):
        respons_dict = {}
        exit()
    value = params[key]
    params_string.append('' if value == 'null' else str(value))
 return '|'.join(params_string)


 __pad__ = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) *    
 chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
__unpad__ = lambda s: s[0:-ord(s[-1])]


 def __encode__(to_encode, iv, key):
 # Pad
 to_encode = __pad__(to_encode)
 # Encrypt
 c = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
 to_encode = c.encrypt(to_encode.encode('utf-8'))
 # Encode
 to_encode = base64.b64encode(to_encode)
 return to_encode.decode("UTF-8")


 def __decode__(to_decode, iv, key):
 # Decode
 to_decode = base64.b64decode(to_decode)
 # Decrypt
 c = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
 to_decode = c.decrypt(to_decode)
 if type(to_decode) == bytes:
    # convert bytes array to str.
    to_decode = to_decode.decode()
 # remove pad
 return __unpad__(to_decode)


 if __name__ == "__main__":
 params = {
    "MID": "mid",
    "ORDER_ID": "order_id",
    "CUST_ID": "cust_id",
    "TXN_AMOUNT": "1",
    "CHANNEL_ID": "WEB",
    "INDUSTRY_TYPE_ID": "Retail",
    "WEBSITE": "xxxxxxxxxxx"
 }

 print(verify_checksum(
    params, 'xxxxxxxxxxxxxxxx',

  "CD5ndX8VVjlzjWbbYoAtKQIlvtXPypQYOg0Fi2AUYKXZA5XSHiRF0FDj7vQu66S8MHx9NaDZ/u
         Ym3WBOWHf+sDQAmTyxqUipA7i1nILlxrk="))

# print(generate_checksum(params, "xxxxxxxxxxxxxxxx"))

可能是什么错误?或者我应该做些什么改变?如果我的商家密钥和 ID 凭据有任何错误,我已经交叉检查了很多次,但没有。

【问题讨论】:

  • 回溯显示错误发生在Checksum.__get_param_string。你需要证明这一点。
  • 感谢您的评论。我已经添加了我的 Checksum.py

标签: python django payment-gateway


【解决方案1】:

您在 params 字典中传递了错误的内容。您引用了 Order,它是类本身,而不是 order,它是您刚刚创建的实例。所以应该是:

   param_dict = {
        'MID': 'my_merchant_id',
        'ORDER_ID': str(order.id),
        'TXN_AMOUNT': order.total_cost,
        'CUST_ID': order.email,
        'INDUSTRY_TYPE_ID': 'Retail',
        'WEBSITE': 'WENSTAGING',
        'CHANNEL_ID': 'WEB',
        'CALLBACK_URL': 'http://127.0.0.1:8000/handlerequest',
    }

(但也请注意,该校验和模块中有很多非常奇怪的东西。为什么用前导和尾随双下划线命名函数?为什么在从 Django 视图调用的函数中调用 exit()?为什么您是否对参数键进行排序,为什么要遍历键然后查找值而不是使用 items() 遍历键值对?实际上,当您大概在寻找 REFUND 时,为什么要进行迭代只在特定的地方?)

【讨论】:

  • 确实如此。不幸的是,我没有对 Checksum.py 进行任何更改,它已经由 paytm 团队进行了。我只是复制粘贴了该文件,还有其他错误,即在解码时未指定“UTF-8”。但这是我可以用来完成这项工作的唯一文件。同样是的,将其更改为 order 确实使该错误消失了,但是当我点击 submit Order button 时。它正在下载一个名为“create”.txt 的文件,而不是重定向到 paytm.html。
  • 但我的回答的第一部分为您详细说明了您需要在视图中更改的内容。
  • 那应该是显示“完成”消息。那是 HttpResponse。但无论如何感谢您清除我对这个线程的实际问题。!
  • 我仍然收到同样的错误,似乎将其更改为订单不起作用。
  • 三个地方都改了吗?
猜你喜欢
  • 2021-09-23
  • 2019-10-22
  • 2019-08-28
  • 2021-02-14
  • 1970-01-01
  • 2021-10-28
  • 2020-09-07
  • 1970-01-01
  • 2019-10-18
相关资源
最近更新 更多