Django implementa la operación de caja de arena de Alipay
El medio ambiente es el módulo requerido
- Django == 3.1.0
- python == 3.7.4
- python-alipay-sdk = 2.0.1
Necesario
- Descargar módulo python-alipay-sdk = 2.0.1
- Documente el SDK de Alipay Python no oficial: https://github.com/fzlee/alipay/blob/master/README.zh-hans.md#alipay.trade.page.pay
Configuración del entorno de zona de pruebas
- En la plataforma abierta Alipay ----> Centro de desarrolladores—> Servicio de desarrollo ----> Sandbox
- La generación y carga de la clave RSA2 se refieren a la dirección oficial: https://opendocs.alipay.com/open/291/105971
- Descargue la dirección de descarga del Asistente de desarrollo de plataforma abierta de Alipay https://opendocs.alipay.com/open/291/introduce para generar una clave secreta después de la descarga [Error en la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de cadena antirrobo, se recomienda guardar la imagen directamente Subir (img-iAJ4s57z-1602600230093) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013215751437.png)]
[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-RLkaGka3-1602600315452) (C:% 5CUsers% 5CASUS% 5CAppData% 5CRoaming% 5CTypora% 5Ctypora-user-images% 5Cimage-20201013215646909.png # pic_center)]
)
4. Copie la clave pública de la aplicación en Alipay.
[Falló la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlink. Se recomienda guardar la imagen y subirla directamente (img-pm1umRDQ-1602600230099) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013220238000.png)]
[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-xIM2Wwqr-1602600230101) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ imagen-20201013220309533.png)]
[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlinking. Se recomienda guardar la imagen y cargarla directamente (img-CZRSx4tY-1602600230104) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ imagen-20201013220359867.png)]
5. Configure la clave secreta del asistente de desarrollo de clave pública de Alipay en la aplicación
- [Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlink. Se recomienda guardar la imagen y subirla directamente (img-hzEeNDd6-1602600230107) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013220610210.png)]
- Cree una carpeta en la aplicación Django y coloque la clave pública de Alipay (la transferencia de la imagen del enlace externo falló, el sitio de origen puede tener un mecanismo de cadena antirrobo, se recomienda guardar la imagen y cargarla directamente (img-Bg9hMEFa-1602600230111) (C: \ Users \ ASUS) \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013221108217.png)]
- Cree una carpeta en la aplicación Django y coloque la clave privada de la plataforma abierta. ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013221548593.png)]
Modelos de Django
# 支付 状态 表 class Status (BaseModel): name = models.CharField (max_length = 32) class Meta: db_table = 'status' # 支付 表 class Order (BaseModel): out_trade_no = models.CharField (max_length = 60) trada_no = models .CharField (max_length = 60, null = True, blank = True) goods = models.ForeignKey (Goods, on_delete = models.CASCADE) user = models.ForeignKey (User, on_delete = models.CASCADE) goods_num = models.IntegerField () status = models.ForeignKey (Status, on_delete = models.CASCADE) class Meta: db_table = 'order'
Configuración de vistas de Django
- 所需 的 包 importar uuid importar redis desde app01.views importar login_serializer desde alipay importar AliPay, AliPayConfig123
# Ruta absoluta para abrir el archivo {} significa avanzar desde aquí app_private_key_string = open ('{} \\ app02 \\ alipay_key \\ app_private_key'.format (settings.BASE_DIR)). Read () alipay_public_key_string = open (' () \\ app02 \\ alipay_key \\ alipay_public'.format (settings.BASE_DIR)). read () 12
[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlinking. Se recomienda guardar la imagen y subirla directamente (img-TU8ck5hJ-1602600230116) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013222520219.png)]
alipay = AliPay ( appid = "2016102500759596", app_notify_url = Ninguno, # predeterminado de devolución de llamada URL app_private_key_string = app_private_key_string, clave pública # Alipay, compruebe que el mensaje de retorno de Alipay se utiliza, no su propia clave pública, alipay_public_key_string = alipay_public_key_string, sign_type = "RSA2 ", # RSA o RSA2 debug = True, # Default False config = AliPayConfig (timeout = 15) # Opcional, request timeout ) 123456789
3. El código comentado se puede eliminar
# Clase de pago AlipayView (APIView): def post (self, request): # print (request.data) token = request.data.get ('token') count = request.data.get ('count') goods_info = request .data.get ('goods_info') # print (goods_info) # El número de pedido uuid es único y único out_trade_no = str (uuid.uuid4 ()) # Importe del pedido inicial total_amount = 0 user_info = login_serializer.loads (token) user_id = user_info. get ('user_id') # Determine si se usa para múltiples ID y divida por número si goods_info.find (',')! = -1: order_list = [] for i in goods_info.split (','): print (i) # lista de adición por lotes # Cycle output id # # Obtener el número de artículos en el carrito de compras # Goods_count = r3.hget (user_id, i) .decode () # # Obtener el artículo igual a i # goods_obj = Goods.objects.get (pk = i) # # Calcular el precio total # total_amount + = int (Goods_obj.price) * int (Goods_count) \ # Tipo de adición de lista order_list.append (Order ( out_trade_no = out_trade_no, Goods_id = i, user_id = user_id, Goods_num = count, status_id = 1, )) print (order_list) ser = Order.objects.bulk_create (order_list) }) # ser.save () else: # print (r3.hget (user_id, Goods_info)) # Goods_count = r3.hget (user_id, Goods_info) .decode () # Goods_obj = Goods.objects.get (pk = Goods_info) # cantidad_total + = int (Goods_obj.price) * int (Goods_count) # print (total_amount) # 单个 添加 ser = OrderModelSer (data = { "out_trade_no": out_trade_no, "Goods": Goods_info, "usuario": user_id, "Goods_num": count, "status": 1 si ser.is_valid (): ser.guardar () más: print (ser.errors) # Subject subject = "京东" # Pago del sitio web de la computadora, debes ir a https://openapi.alipay.com/gateway.do? + order_string order_string = alipay.api_alipay_trade_page_pay ( out_trade_no = out_trade_no, total_amount = count, subject = subject, return_url = "http://127.0.0.1:8000/app02/callback_alipay", notify_url = "http://127.0.0.1:8000/app02/callback_alipay" # Sí Elija, si no completa, use la URL de notificación predeterminada ) # datos cosidos # print (order_string) pay_url = 'https: //openapi.alipaydev.com/gateway.do?'+ order_string # Ruta con salto de parámetro # print (pay_url) return Response ({'pay_url': pay_url, 'msg': 'OK', "código": 200}) 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455566575675
[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-m6WYKp5g-1602600230119) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013223018379.png)]
4.0
# Dirección de devolución de llamada después de la clase de pago CallBackAlipayView (APIView): def get (self, request): print (request.query_params) print ("---------------------- -------- ") # Determinar si hay datos si request.query_params.get (" sign "): # for i in request.query_params.get (" out_trade_no "): # print (request.query_params.get ("out_trade_no")) # Obtener el número de pedido queryset = Order.objects.get (out_trade_no = request.query_params.get ("out_trade_no")) # Modificar el estado del pedido a la modificación parcial comprada ser = OrderModelSer (instance = queryset, data = {"estado": 2}, parcial = Verdadero) si ser.is_valid (): ser.salvar() else: print (ser.errors) return Response ({'msg': 'OK', "data": request.query_params}) 1234567891011121314151617181920
[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo anti-hotlinking. Se recomienda guardar la imagen y subirla directamente (img-AFbrRopL-1602600230122) (C: \ Users \ ASUS \ AppData \ Roaming \ Typora \ typora-user-images \ image-20201013223126443.png)]
Interfaz de llamada
addcart () { dejar datos = nuevo FormData (); data.append ("token", sessionStorage.getItem ("token")) data.append ("goods_info", this.check) data.append ("count", this.count2) axios ({ url: "http: / /127.0.0.1:8000/app02/alipay ", método: 'publicar', datos: datos }). Luego (res => { console.log (res.data) if (res.data.code === 200) { window.location.href = res.data.pay_url } }) }, 12345678910111213141516
1
Página llamada
<template> <div> <div id = "app"> <div class = "header_con"> <div class = "header"> <div class = "welcome fl"> 欢迎 来到 美 多 商城! </div> <div class = "fr"> <div v-if = "username" class = "login_btn fl"> 欢迎 您 : <em> { {username}} </em> <span> | </span> <a @ click = "logout"> 退出 </a> </div> <div v-else class = "login_btn fl"> <a href="login.html"> 登录 </a> <span> | </span> <a href="register.html"> 注册 </a> </div> <div class = "user_link fl"> <span> | </span> <a href="user_center_info.html"> 用户 中心 </a> <span> | </span> <a href="cart.html"> 我 的 购物 车 </a> <span> | </span> <a href="user_center_order.html"> 我 的 订单 </a> </div> </div> </div> </div> <div class = "search_bar clearfix"> <a href="index.html" class="logo fl"> <img src = "/ static / images / logo.png"> </a> <div class = "sub_page_name fl"> | & nbsp; & nbsp; & nbsp ; & nbsp;购物 车 </div> <form method = "get" action = "/ search.html" class = "search_con fr mt40"> <input type = "text" class = "input_text fl" name = "q" placeholder = "搜索 商品 ">form method = "get" action = "/ search.html" class = "search_con fr mt40"> <input type = "submit" class = "input_btn fr" name = "" value = "搜索"> </form> </div> <div class = "total_count"> 全部 商品 <em> { {cart.length}} </ em > 件 </div> <ul class = "cart_list_th clearfix"> <li class = "col01"> 商品 名称 </li> <li class = "col03"> 商品 价格 </li> <li class = "col04" > 数量 </li> <li class = "col05"> 小 计 </li> <li class = "col06"> 操作 </li> </ul> <ul class = "cart_list_td clearfix" v-for = " (sku, índice) en el carrito "> <li class = "col01"> <input type = "checkbox" name = "" v-model = "check": value = "sku.id" @ click = "casilla de verificación (sku.id, sku.count, sku.price ) "> </li> <li class = "col02"> <img: src = "'http://127.0.0.1:8000'+sku.img"> </li> <li class = "col03"> { {sku.name}} </li> <li class = "col05"> { {sku.price}} 元 </li> <li class = "col06"> <div class = "num_add"> <a @click="on_add(sku.id)" class="add fl"> + </a> <input v-model = "sku. count "@ focus =" origin_input = sku.count "@ blur =" on_input (index) "type =" text " class =" num_show fl "> <a @ click =" on_minus (sku.id) "class =" minus fl "> - </a> </div> </li> <li class =" col07 "> { {sku.price * sku.count}} 元 </li> <li class =" col08 "> <a @ click = "del (sku.id)"> 删除 </a> </li> </ul> <li class = "col01"> <input type = "checkbox" @ click = "check_count" v-model = "isChecked"> </li> <li class = "col02"> 全选 </li> <ul class = "asentamientos"> <li class = "col03"> 合计 (不含 运费) : <span> ¥ </span> <em> { {count2}} </em> <br> 共计 <b> { {total_selected_count}} </b> 件 商品 </li> <li class = "col04"> <a @click="addcart"> 去 结算 </a> </li> </ul> </div> <fooder> </fooder> </div> </template> <script> importar axios de 'axios' importar fooder de '../components/Fooder' exportar predeterminado { nombre: "Carrito" datos () { devolver { carrito: [ ], comprobar: [], nombre de usuario: "", total_selected_amount: "", total_selected_count: "", on_selected_all: "", selected_all: "", count2: 0, isChecked: false, } }, componentes: { 'fooder': fooder }, métodos: { del (Goods_id) { let data = new FormData (); data.append ("token", sessionStorage.getItem ("token")) data.append ("Goods_id", Goods_id) axios ({ url: 'http://127.0.0.1:8000/app02/delcart', }). luego (res => { datos: datos console.log (res) this. $ router.go (0) }) }, addcart () { let data = new FormData (); data.append ("token", sessionStorage.getItem ("token")) data.append ("goods_info", this.check) data.append ("count", this.count2) axios ({ url: "http: / /127.0.0.1:8000/app02/alipay ", método: 'publicar', datos: datos }). Luego (res => { console.log (res.data) if (res.data.code === 200) { console.log (res) this. $ router.go (0) window.location.href = res.data.pay_url } }) }, on_add (Goods_id) { dejar datos = new FormData (); data.append ("token", sessionStorage.getItem ("token")) data.append ("Goods_id", Goods_id) axios ({ url: 'http://127.0.0.1:8000/app02/addcart', método: 'post', data: data }). then (res => { }) }, on_minus (Goods_id) { let data = new FormData (); data.append ("token", sessionStorage.getItem ("token")) data.append ("Goods_id", Goods_id) axios ({ url: 'http://127.0.0.1:8000/app02/minuscart', método: 'post', data: data }). luego (res => { console.log (res) this. $ router.go (0) }) }, show () { axios ({ url: 'http://127.0.0.1: 8000 / app02 / showcart ', método:' get ', params: {"token": sessionStorage.getItem ("token ")} }). luego (res => { //127.0.0.1:8000 / app02 / showcart console.log (res) this.cart = res.data.data }) }, // Seleccionar todo y llamar al total Price check_count () { // El valor predeterminado es falso this.count2 = 0; this.check = []; if (this.isChecked) { this.check = [] } else { this.cart.forEach (item => { console.log (item.id); this.check.push (item.id); this.count () }) } }, // Calcular el precio total count () { // let count = 0 if (this.check.includes (gid)) { this.count2 = 0 for (let i in this.cart) { console.log (this.cart [i]) this.count2 + = this.cart [i] .price * this.cart [i] .count } } , // Calcular la casilla de verificación del botón de radio (gid, count, price) { // La primera ejecución está vacía false console.log (this.check) // Si contiene, significa que ha sido seleccionado y haz clic nuevamente para eliminar false y restar el correspondiente Price this.count2 - = count * price this.check.splice (this.check.indexOf (gid), 1) } else { // Empujar significa que agregar se convierte en realidad this.check.push [gid] // Calcula el precio total, selecciona y agrega this.count2 + = count * price } }, }, created () { this.show () } } </script> <style scoped> </style> haz clic para eliminar falso y restar Ir al precio correspondiente this.count2 - = count * price this.check.splice (this.check.indexOf (gid), 1) }, }, } else { // Empujar significa que agregar se convierte en realidad this.check.push [gid] // Calcule el precio total, seleccione y agregue this.count2 + = count * price } created () { this.show () } } </script> <estilo con alcance> </style>
PD: Si necesita materiales de aprendizaje de Python, puede hacer clic en el enlace de abajo para obtenerlo usted mismo.
El código completo se puede obtener haciendo clic en el enlace de abajo ~