使用 Django 支付网关 (Paytm) 时如何修复 "TypeError at /orders/create/ argument of type 'DeferredAttribute' is not iterable"
How to fix "TypeError at /orders/create/ argument of type 'DeferredAttribute' is not iterable" when using Django Payment Gateway (Paytm)
我的问题是在我的电子商务项目中实施支付网关。我使用的支付网关来自印度国家 "Paytm"。
访问他们的网站后,https://developer.paytm.com/docs/v1/payment-gateway。
我收集了我的测试 ID 和密钥。
我有一个结帐页面,一旦用户输入 his/her 详细信息。他被重定向到一个带有订单 ID 的成功订购页面。
一切正常。
但是,现在当我开始实施我的支付网关时,我 运行 在我的 views.py 订单应用文件中出现错误 "argument of type 'DeferredAttribute' is not iterable"。
首先我用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})
服务器 运行s 没有任何错误。
但是错误输出是:
Error
这是我的 html 页面。
post Url link 由 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>
Checksum.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 凭证有任何错误,我已经多次交叉检查,但没有。
您在参数字典中传递了错误的内容。您引用了 Order
,这是 class 本身,而不是 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',
}
(但还要注意,校验和模块中有很多非常奇怪的东西。为什么要用前导和尾随 double-underscores 命名函数?为什么要在调用的函数中调用 exit()
从 Django 的角度来看?为什么要对参数键进行排序,为什么要遍历键然后查找值而不是遍历 key-value 与 items()
对?事实上你为什么当您可能仅在特定位置寻找退款时,是否进行迭代?)
我的问题是在我的电子商务项目中实施支付网关。我使用的支付网关来自印度国家 "Paytm"。
访问他们的网站后,https://developer.paytm.com/docs/v1/payment-gateway。
我收集了我的测试 ID 和密钥。
我有一个结帐页面,一旦用户输入 his/her 详细信息。他被重定向到一个带有订单 ID 的成功订购页面。 一切正常。
但是,现在当我开始实施我的支付网关时,我 运行 在我的 views.py 订单应用文件中出现错误 "argument of type 'DeferredAttribute' is not iterable"。
首先我用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})
服务器 运行s 没有任何错误。
但是错误输出是:
Error
这是我的 html 页面。 post Url link 由 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>
Checksum.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 凭证有任何错误,我已经多次交叉检查,但没有。
您在参数字典中传递了错误的内容。您引用了 Order
,这是 class 本身,而不是 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',
}
(但还要注意,校验和模块中有很多非常奇怪的东西。为什么要用前导和尾随 double-underscores 命名函数?为什么要在调用的函数中调用 exit()
从 Django 的角度来看?为什么要对参数键进行排序,为什么要遍历键然后查找值而不是遍历 key-value 与 items()
对?事实上你为什么当您可能仅在特定位置寻找退款时,是否进行迭代?)