发布于 2026-01-06 1 阅读
0

在 Django 中集成 Paytm 支付网关

在 Django 中集成 Paytm 支付网关

在 Django 中集成 Paytm 支付网关

在 Django 中集成 Paytm 支付网关

简介:这是学习如何在 Django 应用中集成支付功能的绝佳途径。Paytm 的官方文档在

注意:您需要拥有 Paytm 商户账户才能使用支付网关。

以下文档中提到了向网关发送请求的过程:

图片来源:Paytm

我们将从零开始创建一个 Django 应用来实现我们的目标。

步骤 0:设置项目

首先,我们将为我们的项目创建一个虚拟环境。

# Install Django & virtualenv if not already
$ pip install Django virtualenv
# create a new Django project
$ django-admin startproject pay2me
$ cd pay2me
# Initialize a new virtualenv with Py3 since Python 2 is dead
$ virtualenv env --python=python3
# Activate the virtual environment and intall Django
$ source ./env/bin/activate
(env)$ pip install Django
Enter fullscreen mode Exit fullscreen mode

您可以使用该命令$ source ./env/bin/activate激活虚拟环境。

为了节省时间,我们将使用默认的 Django 用户模型进行身份验证,但如果您愿意,也可以使用自定义用户模型。

现在让我们为项目添加登录视图。打开pay2me/urls.py并向登录/注销视图添加条目。

from django.contrib.auth.views import LoginView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', LoginView.as_view(), name='login'),
]
Enter fullscreen mode Exit fullscreen mode

现在要创建登录和注销页面,我们首先需要迁移更改并创建一个超级用户。请在终端中运行以下命令。

(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
(env)$ python manage.py createsuperuser
Enter fullscreen mode Exit fullscreen mode

现在我们可以通过执行命令来运行服务器python manage.py runserver,然后访问http://localhost:8000/login来查看登录页面。

由于缺少登录页面模板,页面将无法加载,因此我们将创建一个模板LoginViewtemplates在项目根目录下创建一个目录,并registration在该目录下创建另一个目录。现在,在该目录中templates添加一个文件,并将以下内容添加到该文件中。login.htmlregistration

<!DOCTYPE html>
<head>
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Login</button>
    </form>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

登录页面包含一个表单和一个csrf_token,该令牌将由系统提供,LoginView因此我们不必担心。

我们还需要进行一些修改pay2me/settings.py。打开文件,找到TEMPLATES设置并添加'templates'DIRS列表中,它应该看起来像这样:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
Enter fullscreen mode Exit fullscreen mode

这将有助于 Django 找到我们的registration/login.html模板。

模板已全部设置完毕,现在重启服务器并访问http://localhost:8000/login,登录表单应如下所示:

登录页面

我们继续进行下一步。

第一步:制作用户界面

为了保持简洁,本文只有两页:

  • 支付页面:我们将在此处输入需要支付的金额。
  • 回调页面:从 Paytm 收到的包含支付状态的响应

让我们先创建一个新应用来组织这些功能。

(env)$ python manage.py startapp payments
Enter fullscreen mode Exit fullscreen mode

首先,让我们将支付应用添加到项目中。为此,我们将把它添加'payments'INSTALLED_APPS列表中pay2me/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'payments',
]
Enter fullscreen mode Exit fullscreen mode

现在让我们把模板文件添加pay.html支付应用程序目录callback.htmltemplates/payments

pay.html
<!DOCTYPE html>

<head>
    <title>Payment Home</title>
</head>

<body>
    <h2>Payment Home</h2>
    {% if error %}
    <h3>{{ error }}</h3>
    {% endif %}
    <form method="post">
        {% csrf_token %}
        <label for="username">Username: </label>
        <input type="text" name="username" required>
        <label for="password">Password: </label>
        <input type="text" name="password" required>
        <label for="amount">Amount: </label>
        <input type="number" name="amount" value="100">
        <input type="submit" name="submit" value="Submit" required>
    </form>
</body>

</html>

Enter fullscreen mode Exit fullscreen mode
回调.html
<!DOCTYPE html>
<head>
    <title>Callback</title>
</head>
<body>
    <h2>Callback Messsage: </h2>                    <br>
    <h3> Checksum Verification: {{ message }} </h3> <br>
    MID: {{ MID }}                                  <br>
    TXNID: {{ TXNID }}                              <br>
    ORDERID: {{ ORDERID }}                          <br>
    BANKTXNID: {{ BANKTXNID }}                      <br>
    TXNAMOUNT: {{ TXNAMOUNT }}                      <br>
    CURRENCY: {{ CURRENCY }}                        <br>
    <h3> STATUS: {{ STATUS }} </h3>                 <br>
    RESPCODE: {{ RESPCODE }}                        <br>
    RESPMSG: {{ RESPMSG }}                          <br>
    TXNDATE: {{ TXNDATE }}                          <br>
    GATEWAYNAME: {{ GATEWAYNAME }}                  <br>
    BANKNAME: {{ BANKNAME }}                        <br>
    BIN_NAME: {{ BIN_NAME }}                        <br>
    PAYMENTMODE: {{ PAYMENTMODE }}                  <br>
    CHECKSUMHASH: {{ CHECKSUMHASH }}
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

支付页面会要求用户输入登录信息和支付金额,而回调页面则会显示 Paytm 在支付完成后提供的众多参数值。

步骤 2:创建交易模型

由于任何与支付相关的应用程序都需要交易,我们将按如下方式创建交易模型payments/models.py

from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

class Transaction(models.Model):
    made_by = models.ForeignKey(User, related_name='transactions', 
                                on_delete=models.CASCADE)
    made_on = models.DateTimeField(auto_now_add=True)
    amount = models.IntegerField()
    order_id = models.CharField(unique=True, max_length=100, null=True, blank=True)
    checksum = models.CharField(max_length=100, null=True, blank=True)

    def save(self, *args, **kwargs):
        if self.order_id is None and self.made_on and self.id:
            self.order_id = self.made_on.strftime('PAY2ME%Y%m%dODR') + str(self.id)
        return super().save(*args, **kwargs)

Enter fullscreen mode Exit fullscreen mode

交易模型定义中,order_id是唯一的,并根据交易日期生成。我们可以看到,其中包含一个校验和,用于存储 Python 文件生成的校验和。

我们重写了该方法,使其能够根据交易的日期和时间save自动生成。order_id

让我们再次运行迁移,将事务模型添加到数据库中。

(env)$ python manage.py makemigration
(env)$ python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

步骤 3:添加 Paytm 设置

添加以下设置pay2me/settings.py

PAYTM_MERCHANT_ID = '<your_merchant_id>'
PAYTM_SECRET_KEY = '<your_paytm_secret_key>'
PAYTM_WEBSITE = 'WEBSTAGING'
PAYTM_CHANNEL_ID = 'WEB'
PAYTM_INDUSTRY_TYPE_ID = 'Retail'
Enter fullscreen mode Exit fullscreen mode

第四步:创建支付视图

Paytm在这里提供了一个校验和生成代码库,但该代码使用的是已弃用的库pycrypto。以下代码包含与最新pycryptodome库兼容的修改后的文件。请下载该文件payments并将其以文件名保存到您的应用程序paytm.py

现在我们来创建initiate_payment接收用户名、密码和金额的视图。打开payments/views.py并添加以下代码。

from django.shortcuts import render
from django.contrib.auth import authenticate, login as auth_login
from django.conf import settings
from .models import Transaction
from .paytm import generate_checksum, verify_checksum


def initiate_payment(request):
    if request.method == "GET":
        return render(request, 'payments/pay.html')
    try:
        username = request.POST['username']
        password = request.POST['password']
        amount = int(request.POST['amount'])
        user = authenticate(request, username=username, password=password)
        if user is None:
            raise ValueError
        auth_login(request=request, user=user)
    except:
        return render(request, 'payments/pay.html', context={'error': 'Wrong Accound Details or amount'})

    transaction = Transaction.objects.create(made_by=user, amount=amount)
    transaction.save()
    merchant_key = settings.PAYTM_SECRET_KEY

    params = (
        ('MID', settings.PAYTM_MERCHANT_ID),
        ('ORDER_ID', str(transaction.order_id)),
        ('CUST_ID', str(transaction.made_by.email)),
        ('TXN_AMOUNT', str(transaction.amount)),
        ('CHANNEL_ID', settings.PAYTM_CHANNEL_ID),
        ('WEBSITE', settings.PAYTM_WEBSITE),
        # ('EMAIL', request.user.email),
        # ('MOBILE_N0', '9911223388'),
        ('INDUSTRY_TYPE_ID', settings.PAYTM_INDUSTRY_TYPE_ID),
        ('CALLBACK_URL', 'http://127.0.0.1:8000/callback/'),
        # ('PAYMENT_MODE_ONLY', 'NO'),
    )

    paytm_params = dict(params)
    checksum = generate_checksum(paytm_params, merchant_key)

    transaction.checksum = checksum
    transaction.save()

    paytm_params['CHECKSUMHASH'] = checksum
    print('SENT: ', checksum)
    return render(request, 'payments/redirect.html', context=paytm_params)

Enter fullscreen mode Exit fullscreen mode

让我们逐部分地理解这​​个观点:

def initiate_payment(request):
    if request.method == "GET":
        return render(request, 'payments/pay.html')
Enter fullscreen mode Exit fullscreen mode

第一步是检查请求方法。如果请求方法是GET,那么我们就直接返回支付页面。

try:
        username = request.POST['username']
        password = request.POST['password']
        amount = int(request.POST['amount'])
        user = authenticate(request, username=username, password=password)
        if user is None:
            raise ValueError
        auth_login(request=request,     user=user)
    except:
        return render(request, 'payments/pay.html', context={'error': 'Wrong Account Details or amount'})
Enter fullscreen mode Exit fullscreen mode

然后,我们会验证用户在表单中输入的用户名和密码,并尝试登录。如果登录信息无效,则视图会返回登录页面并显示错误消息。

    transaction = Transaction.objects.create(made_by=user, amount=amount)
    transaction.save()
    merchant_key = settings.PAYTM_SECRET_KEY
Enter fullscreen mode Exit fullscreen mode

接下来,我们为用户创建一个 Transaction 对象,并从中获取商户密钥settings.py

    params = (
        ('MID', settings.PAYTM_MERCHANT_ID),
        ('ORDER_ID', str(transaction.order_id)),
        ('CUST_ID', str(transaction.made_by.email)),
        ('TXN_AMOUNT', str(transaction.amount)),
        ('CHANNEL_ID', settings.PAYTM_CHANNEL_ID),
        ('WEBSITE', settings.PAYTM_WEBSITE),
        # ('EMAIL', request.user.email),
        # ('MOBILE_N0', '9911223388'),
        ('INDUSTRY_TYPE_ID', settings.PAYTM_INDUSTRY_TYPE_ID),
        ('CALLBACK_URL', 'http://127.0.0.1:8000/callback/'),
        # ('PAYMENT_MODE_ONLY', 'NO'),
    )
    paytm_params = dict(params)

Enter fullscreen mode Exit fullscreen mode

然后我们为Paytm 校验和生成器创建所有设置,以便生成校验和。

    checksum = generate_checksum(paytm_params, merchant_key)

    transaction.checksum = checksum
    transaction.save()

    paytm_params['CHECKSUMHASH'] = checksum

Enter fullscreen mode Exit fullscreen mode

接下来,在生成校验和之后,我们将校验和添加到paytm_params字典和Transaction对象中。

    return render(request, 'payment/redirect.html', context=paytm_params)

Enter fullscreen mode Exit fullscreen mode

最后我们返回redirect页面。

步骤 5:创建重定向页面

创建重定向页面payments/templates/payments/redirect.html

<html>
    <head>
        <title>Merchant Check Out Page</title>
    </head>
    <body>
        <h1>Please do not refresh this page...</h1>
        <form method="post" action="https://securegw-stage.paytm.in/order/process/" name="f1">
            <table>
                <tbody>
                    <input type="hidden" name="MID" value="{{ MID }}">
                    <input type="hidden" name="WEBSITE" value="{{ WEBSITE }}">
                    <input type="hidden" name="ORDER_ID" value="{{ ORDER_ID }}">
                    <input type="hidden" name="CUST_ID" value="{{ CUST_ID }}">
                    <input type="hidden" name="INDUSTRY_TYPE_ID" value="{{ INDUSTRY_TYPE_ID }}">
                    <input type="hidden" name="CHANNEL_ID" value="{{ CHANNEL_ID }}">
                    <input type="hidden" name="TXN_AMOUNT" value="{{ TXN_AMOUNT }}">
                    <input type="hidden" name="CALLBACK_URL" value="{{ CALLBACK_URL }}">
                    <input type="hidden" name="CHECKSUMHASH" value="{{ CHECKSUMHASH }}">
                </tbody>
            </table>
        <script type="text/javascript">
            document.f1.submit();
        </script>
        </form>
    </body>
</html>

Enter fullscreen mode Exit fullscreen mode

重定向页面包含一个简单的表单,其中包含字典中的字段。我们使用 JavaScript 代码自动将表单提交到 Paytm 网关。

步骤 6:创建回调视图

回调视图是指当 Paytm 返回交易状态时将被调用的视图。

在以下回调视图中添加payments/views.py

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def callback(request):
    if request.method == 'POST':
        received_data = dict(request.POST)
        paytm_params = {}
        paytm_checksum = received_data['CHECKSUMHASH'][0]
        for key, value in received_data.items():
            if key == 'CHECKSUMHASH':
                paytm_checksum = value[0]
            else:
                paytm_params[key] = str(value[0])
        # Verify checksum
        is_valid_checksum = verify_checksum(paytm_params, settings.PAYTM_SECRET_KEY, str(paytm_checksum))
        if is_valid_checksum:
            received_data['message'] = "Checksum Matched"
        else:
            received_data['message'] = "Checksum Mismatched"
            return render(request, 'payments/callback.html', context=received_data)
        return render(request, 'payments/callback.html', context=received_data)


Enter fullscreen mode Exit fullscreen mode

回调视图接收来自 Paytm 服务器的 POST 请求。然后,我们将接收到的数据检索到一个字典中,并验证 Paytm 发送的校验和,以防止伪造请求。之后,我们返回包含交易详情和消息的页面。

步骤 7:创建路由。

最后一步,我们来创建视图的URL,结束这篇冗长的教程。urls.py在支付应用中创建/打开。添加以下路由。

from django.urls import path
from .views import initiate_payment, callback

urlpatterns = [
    path('pay/', initiate_payment, name='pay'),
    path('callback/', callback, name='callback'),
]


Enter fullscreen mode Exit fullscreen mode

现在让我们把这些网址添加到……pay2me/urls.py

from django.urls import include
urlpatterns = [
    # include 
    path('', include('payments.urls'))
]

Enter fullscreen mode Exit fullscreen mode

测试运行:试用一种支付方式

现在让我们运行python manage.py runserver并访问http://localhost:8000/pay/来创建付款。

请填写表格。

支付页面

这将跳转到 Paytm 支付网关。请使用任意虚拟支付方式。

Paytm支付网关

您还可以选择交易状态(成功/失败)。

银行演示页面

最后您将进入回调页面,该页面将显示交易状态。

回调页面

Github:示例

以下是GitHub上上述示例代码的链接。

文章来源:https://dev.to/iiits-iota/paytm- payment-gateway-integration-in-django-1657