Integrating Alipay Sandbox with Django REST Framework and Vue

Setting Up Alipay Sandbox Environment

  1. Create an Application Log in to the Ant Financial Open Platform and navigate to the Management Center -> Application List.

    https://open.alipay.com/platform/home.htm
    

    After creating the application, you will receive an appid. Note that production Alipay payments require enterprise verification, so we use the sandbox environment for development and testing.

  2. Sandbox Environment Access the sandbox application page at:

    https://openhome.alipay.com/platform/appDaily.htm?tab=info
    
  3. Generate Public and Private Keys Follow the official guide at https://docs.open.alipay.com/291/105971/ to generate RSA2 keys using the provided tool. For Windows, use the Windows version; for Linux, use the Linux version.

  4. Place Key Files

    • Copy the generated private key to trade/keys/private_2048.txt and add the following header and footer:
      -----BEGIN PRIVATE KEY-----
      -----END PRIVATE KEY-----
      
    • Copy the Alipay public key to trade/keys/alipay_key_2048.txt and add similar header/footer.

Alipay API Documentation

We use the Computer Website Payment API. The main documentation is at https://docs.open.alipay.com/270. Specifically, we use the alipay.trade.page.pay interface.

Important Parameters

Implementing the Payment Flow

  1. Install Required Module

    pip install pycryptodome
    
  2. Create the Alipay Utility Class Create utils/alipay.py with the following code:

# -*- coding: utf-8 -*-

from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytes
import json


class AliPay(object):
    """
    Alipay payment interface
    """
    def __init__(self, appid, app_notify_url, app_private_key_path,
                 alipay_public_key_path, return_url, debug=False):
        self.appid = appid
        self.app_notify_url = app_notify_url
        self.app_private_key_path = app_private_key_path
        self.app_private_key = None
        self.return_url = return_url
        with open(self.app_private_key_path) as fp:
            self.app_private_key = RSA.importKey(fp.read())

        self.alipay_public_key_path = alipay_public_key_path
        with open(self.alipay_public_key_path) as fp:
            self.alipay_public_key = RSA.import_key(fp.read())

        if debug is True:
            self.__gateway = "https://openapi.alipaydev.com/gateway.do"
        else:
            self.__gateway = "https://openapi.alipay.com/gateway.do"

    def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
        biz_content = {
            "subject": subject,
            "out_trade_no": out_trade_no,
            "total_amount": total_amount,
            "product_code": "FAST_INSTANT_TRADE_PAY",
        }
        biz_content.update(kwargs)
        data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
        return self.sign_data(data)

    def build_body(self, method, biz_content, return_url=None):
        data = {
            "app_id": self.appid,
            "method": method,
            "charset": "utf-8",
            "sign_type": "RSA2",
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "version": "1.0",
            "biz_content": biz_content
        }
        if return_url is not None:
            data["notify_url"] = self.app_notify_url
            data["return_url"] = self.return_url
        return data

    def sign_data(self, data):
        data.pop("sign", None)
        unsigned_items = self.ordered_data(data)
        unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
        sign = self.sign(unsigned_string.encode("utf-8"))
        quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)
        signed_string = quoted_string + "&sign=" + quote_plus(sign)
        return signed_string

    def ordered_data(self, data):
        complex_keys = []
        for key, value in data.items():
            if isinstance(value, dict):
                complex_keys.append(key)
        for key in complex_keys:
            data[key] = json.dumps(data[key], separators=(',', ':'))
        return sorted([(k, v) for k, v in data.items()])

    def sign(self, unsigned_string):
        key = self.app_private_key
        signer = PKCS1_v1_5.new(key)
        signature = signer.sign(SHA256.new(unsigned_string))
        sign = encodebytes(signature).decode("utf8").replace("\n", "")
        return sign

    def _verify(self, raw_content, signature):
        key = self.alipay_public_key
        signer = PKCS1_v1_5.new(key)
        digest = SHA256.new()
        digest.update(raw_content.encode("utf8"))
        if signer.verify(digest, decodebytes(signature.encode("utf8"))):
            return True
        return False

    def verify(self, data, signature):
        if "sign_type" in data:
            sign_type = data.pop("sign_type")
        unsigned_items = self.ordered_data(data)
        message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
        return self._verify(message, signature)
  1. Test the Payment URL Run the script to generate a payment URL and test with sandbox account credentials.

Integrating with Django

  1. Confgiure URLs

    url('alipay/return/', AlipayView.as_view())
    
  2. Update alipay.py with Remote URLs Set return_url and app_notify_url to the server's endpoitns, e.g.:

    return_url="http://your-server-ip:8000/alipay/return/"
    app_notify_url="http://your-server-ip:8000/alipay/return/"
    
  3. Add Key Paths to Settings In settings.py:

    private_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/private_2048.txt')
    ali_pub_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/alipay_key_2048.txt')
    
  4. Implement the Alipay View In trade/views.py:

from datetime import datetime
from utils.alipay import AliPay
from rest_framework.views import APIView
from MxShop.settings import ali_pub_key_path, private_key_path
from rest_framework.response import Response
from django.shortcuts import redirect

class AlipayView(APIView):
    def get(self, request):
        """Handle Alipay return_url"""
        processed_dict = {}
        for key, value in request.GET.items():
            processed_dict[key] = value
        sign = processed_dict.pop("sign", None)

        alipay = AliPay(
            appid="2016090900469819",
            app_notify_url="http://your-server-ip:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,
            debug=True,
            return_url="http://your-server-ip:8000/alipay/return/"
        )

        verify_re = alipay.verify(processed_dict, sign)
        if verify_re is True:
            response = redirect("index")
            response.set_cookie("nextPath", "pay", max_age=3)
            return response
        else:
            response = redirect("index")
            return response

    def post(self, request):
        """Handle Alipay notify_url"""
        processed_dict = {}
        for key, value in request.POST.items():
            processed_dict[key] = value
        sign = processed_dict.pop("sign", None)

        alipay = AliPay(
            appid="2016090900469819",
            app_notify_url="http://your-server-ip:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,
            debug=True,
            return_url="http://your-server-ip:8000/alipay/return/"
        )

        verify_re = alipay.verify(processed_dict, sign)
        if verify_re is True:
            order_sn = processed_dict.get('out_trade_no', None)
            trade_no = processed_dict.get('trade_no', None)
            trade_status = processed_dict.get('trade_status', None)

            existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
            for existed_order in existed_orders:
                order_goods = existed_order.goods.all()
                for order_good in order_goods:
                    goods = order_good.goods
                    goods.sold_num += order_good.goods_num
                    goods.save()
                existed_order.pay_status = trade_status
                existed_order.trade_no = trade_no
                existed_order.pay_time = datetime.now()
                existed_order.save()
            return Response("success")
  1. Add Payment URL to Serializers In trade/serializers.py, add a SerializerMethodField to generate the Alipay payment URL:
class OrderSerializer(serializers.ModelSerializer):
    alipay_url = serializers.SerializerMethodField(read_only=True)

    def get_alipay_url(self, obj):
        alipay = AliPay(
            appid="2016090900469819",
            app_notify_url="http://your-server-ip:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,
            debug=True,
            return_url="http://your-server-ip:8000/alipay/return/"
        )
        url = alipay.direct_pay(
            subject=obj.order_sn,
            out_trade_no=obj.order_sn,
            total_amount=obj.order_mount,
        )
        re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)
        return re_url

Deploying Vue Static Files with Django

  1. Build Vue Project Run cnpm run build to generate static files in the dist directory.

  2. Copy Files

    • Copy index.html to Django's templates directory.
    • Copy dist/static contents to Django's static directory.
    • Copy index.entry.js to the Django static directory.
  3. Configure Static Files in settings.py

    STATIC_URL = '/static/'
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, "static"),
    )
    
  4. Update index.html Change the script source to:

    <script type="text/javascript" src="/static/index.entry.js"></script>
    
  5. Configure URL for Index In urls.py:

    from django.views.generic import TemplateView
    urlpatterns = [
        url(r'^index/', TemplateView.as_view(template_name="index.html"), name="index"),
    ]
    
  6. Update the Return URL Redirect Ensure the AlipayView.get method redirects appropriately.

After deploying these changes, the application should be accessible via the index URL. Users can add products to the cart, proceed to checkout, create orders, and be redirected to the Alipay sandbox payment page.

Tags: Django rest framework vue alipay Payment Integration

Posted on Fri, 11 Sep 2026 16:08:48 +0000 by cloudhybrid