【Vue+Django REST framework实战】第9章—— 购物车、订单管理和支付功能

编程入门 行业动态 更新时间:2024-10-10 23:23:48

【Vue+Django REST framework实战】第9章—— <a href=https://www.elefans.com/category/jswz/34/1770732.html style=购物车、订单管理和支付功能"/>

【Vue+Django REST framework实战】第9章—— 购物车、订单管理和支付功能

购物车功能需求分析和加入到购物车实现

#购物车url
router.register(r'shopcarts', ShoppingCartViewset, base_name="shopcarts")
class ShoppingCartViewset(viewsets.ModelViewSet):"""购物车功能list:获取购物车详情create:加入购物车delete:删除购物记录"""permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)serializer_class = ShopCartSerializerlookup_field = "goods_id"def perform_create(self, serializer):shop_cart = serializer.save()goods = shop_cart.goodsgoods.goods_num -= shop_cart.numsgoods.save()def perform_destroy(self, instance):goods = instance.goodsgoods.goods_num += instance.numsgoods.save()instance.delete()def perform_update(self, serializer):existed_record = ShoppingCart.objects.get(id=serializer.instance.id)existed_nums = existed_record.numssaved_record = serializer.save()nums = saved_record.nums-existed_numsgoods = saved_record.goodsgoods.goods_num -= numsgoods.save()def get_serializer_class(self):if self.action == 'list':return ShopCartDetailSerializerelse:return ShopCartSerializerdef get_queryset(self):return ShoppingCart.objects.filter(user=self.request.user)
class ShopCartDetailSerializer(serializers.ModelSerializer):goods = GoodsSerializer(many=False, read_only=True)class Meta:model = ShoppingCartfields = ("goods", "nums")class ShopCartSerializer(serializers.Serializer):user = serializers.HiddenField(default=serializers.CurrentUserDefault())nums = serializers.IntegerField(required=True, label="数量",min_value=1,error_messages={"min_value":"商品数量不能小于一","required": "请选择购买数量"})goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())def create(self, validated_data):user = self.context["request"].usernums = validated_data["nums"]goods = validated_data["goods"]existed = ShoppingCart.objects.filter(user=user, goods=goods)if existed:existed = existed[0]existed.nums += numsexisted.save()else:existed = ShoppingCart.objects.create(**validated_data)return existeddef update(self, instance, validated_data):#修改商品数量instance.nums = validated_data["nums"]instance.save()return instance

订单管理接口

#订单相关url
router.register(r'orders', OrderViewset, base_name="orders")
class OrderViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):"""订单管理list:获取个人订单delete:删除订单create:新增订单"""permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)serializer_class = OrderSerializerdef get_queryset(self):return OrderInfo.objects.filter(user=self.request.user)def get_serializer_class(self):if self.action == "retrieve":return OrderDetailSerializerreturn OrderSerializerdef perform_create(self, serializer):order = serializer.save()shop_carts = ShoppingCart.objects.filter(user=self.request.user)for shop_cart in shop_carts:order_goods = OrderGoods()order_goods.goods = shop_cart.goodsorder_goods.goods_num = shop_cart.numsorder_goods.order = orderorder_goods.save()shop_cart.delete()return order
class OrderDetailSerializer(serializers.ModelSerializer):goods = OrderGoodsSerialzier(many=True)alipay_url = serializers.SerializerMethodField(read_only=True)def get_alipay_url(self, obj):alipay = AliPay(appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")url = alipay.direct_pay(subject=obj.order_sn,out_trade_no=obj.order_sn,total_amount=obj.order_mount,)re_url = ".do?{data}".format(data=url)return re_urlclass Meta:model = OrderInfofields = "__all__"class OrderSerializer(serializers.ModelSerializer):user = serializers.HiddenField(default=serializers.CurrentUserDefault())pay_status = serializers.CharField(read_only=True)trade_no = serializers.CharField(read_only=True)order_sn = serializers.CharField(read_only=True)pay_time = serializers.DateTimeField(read_only=True)alipay_url = serializers.SerializerMethodField(read_only=True)def get_alipay_url(self, obj):alipay = AliPay(appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")url = alipay.direct_pay(subject=obj.order_sn,out_trade_no=obj.order_sn,total_amount=obj.order_mount,)re_url = ".do?{data}".format(data=url)return re_urldef generate_order_sn(self):# 当前时间+userid+随机数from random import Randomrandom_ins = Random()order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),userid=self.context["request"].user.id, ranstr=random_ins.randint(10, 99))return order_sndef validate(self, attrs):attrs["order_sn"] = self.generate_order_sn()return attrsclass Meta:model = OrderInfofields = "__all__"

pycharm远程代码调试

支付宝通知接口验证

# -*- coding: utf-8 -*-# pip install pycryptodome
__author__ = 'bobby'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, encodebytesimport jsonclass AliPay(object):"""支付宝支付接口"""def __init__(self, appid, app_notify_url, app_private_key_path,alipay_public_key_path, return_url, debug=False):self.appid = appidself.app_notify_url = app_notify_urlself.app_private_key_path = app_private_key_pathself.app_private_key = Noneself.return_url = return_urlwith open(self.app_private_key_path) as fp:self.app_private_key = RSA.importKey(fp.read())self.alipay_public_key_path = alipay_public_key_pathwith open(self.alipay_public_key_path) as fp:self.alipay_public_key = RSA.import_key(fp.read())if debug is True:self.__gateway = ".do"else:self.__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",# "qr_pay_mode":4}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_urldata["return_url"] = self.return_urlreturn datadef 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"))# ordered_items = self.ordered_data(data)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_stringdef ordered_data(self, data):complex_keys = []for key, value in data.items():if isinstance(value, dict):complex_keys.append(key)# 将字典类型的数据dump出来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_keysigner = PKCS1_v1_5.new(key)signature = signer.sign(SHA256.new(unsigned_string))# base64 编码,转换为unicode表示并移除回车sign = encodebytes(signature).decode("utf8").replace("\n", "")return signdef _verify(self, raw_content, signature):# 开始计算签名key = self.alipay_public_keysigner = PKCS1_v1_5.new(key)digest = SHA256.new()digest.update(raw_content.encode("utf8"))if signer.verify(digest, decodebytes(signature.encode("utf8"))):return Truereturn Falsedef 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)if __name__ == "__main__":return_url = 'http://127.0.0.1:8000/?total_amount=100.00&timestamp=2017-08-15+23%3A53%3A34&sign=e9E9UE0AxR84NK8TP1CicX6aZL8VQj68ylugWGHnM79zA7BKTIuxxkf%2FvhdDYz4XOLzNf9pTJxTDt8tTAAx%2FfUAJln4WAeZbacf1Gp4IzodcqU%2FsIc4z93xlfIZ7OLBoWW0kpKQ8AdOxrWBMXZck%2F1cffy4Ya2dWOYM6Pcdpd94CLNRPlH6kFsMCJCbhqvyJTflxdpVQ9kpH%2B%2Fhpqrqvm678vLwM%2B29LgqsLq0lojFWLe5ZGS1iFBdKiQI6wZiisBff%2BdAKT9Wcao3XeBUGigzUmVyEoVIcWJBH0Q8KTwz6IRC0S74FtfDWTafplUHlL%2Fnf6j%2FQd1y6Wcr2A5Kl6BQ%3D%3D&trade_no=2017081521001004340200204115&sign_type=RSA2&auth_app_id=2016080600180695&charset=utf-8&seller_id=2088102170208070&method=alipay.trade.page.pay.return&app_id=2016080600180695&out_trade_no=20170202185&version=1.0'o = urlparse(return_url)query = parse_qs(o.query)processed_query = {}ali_sign = query.pop("sign")[0]alipay = AliPay(appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path="../trade/keys/private_2048.txt",alipay_public_key_path="../trade/keys/alipay_key_2048.txt",  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")for key, value in query.items():processed_query[key] = value[0]print (alipay.verify(processed_query, ali_sign))url = alipay.direct_pay(subject="测试订单2",out_trade_no="20170202sss",total_amount=100,return_url="http://127.0.0.1:8000/alipay/return/")re_url = ".do?{data}".format(data=url)print(re_url)

django集成支付宝notify_url和return_url接口

 url(r'^alipay/return/', AlipayView.as_view(), name="alipay"),
from rest_framework.views import APIView
from utils.alipay import AliPay
from MxShop.settings import ali_pub_key_path, private_key_path
from rest_framework.response import Response
class AlipayView(APIView):def get(self, request):"""处理支付宝的return_url返回:param request::return:"""processed_dict = {}for key, value in request.GET.items():processed_dict[key] = valuesign = processed_dict.pop("sign", None)alipay = AliPay(appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1: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:existed_order.pay_status = trade_statusexisted_order.trade_no = trade_noexisted_order.pay_time = datetime.now()existed_order.save()from django.shortcuts import redirect	response = redirect("index")		# 重定向。通过name=index的url中指定的template中的静态文件,生成新的html页面返回给前端response.set_cookie("nextPath","pay", max_age=3)	# 有效时间3秒return responseelse:response = redirect("index")return responsedef post(self, request):"""处理支付宝的notify_url:param request::return:"""processed_dict = {}for key, value in request.POST.items():processed_dict[key] = valuesign = processed_dict.pop("sign", None)alipay = AliPay(appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1: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.goodsgoods.sold_num += order_good.goods_numgoods.save()existed_order.pay_status = trade_statusexisted_order.trade_no = trade_noexisted_order.pay_time = datetime.now()existed_order.save()return Response("success")
class OrderSerializer(serializers.ModelSerializer):user = serializers.HiddenField(default=serializers.CurrentUserDefault())pay_status = serializers.CharField(read_only=True)trade_no = serializers.CharField(read_only=True)order_sn = serializers.CharField(read_only=True)pay_time = serializers.DateTimeField(read_only=True)alipay_url = serializers.SerializerMethodField(read_only=True)def get_alipay_url(self, obj):alipay = AliPay(appid="",app_notify_url="http://127.0.0.1:8000/alipay/return/",app_private_key_path=private_key_path,alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,debug=True,  # 默认False,return_url="http://127.0.0.1:8000/alipay/return/")url = alipay.direct_pay(subject=obj.order_sn,out_trade_no=obj.order_sn,total_amount=obj.order_mount,)re_url = ".do?{data}".format(data=url)return re_urldef generate_order_sn(self):# 当前时间+userid+随机数from random import Randomrandom_ins = Random()order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),userid=self.context["request"].user.id, ranstr=random_ins.randint(10, 99))return order_sndef validate(self, attrs):attrs["order_sn"] = self.generate_order_sn()return attrsclass Meta:model = OrderInfofields = "__all__"

支付成功后回调到支付前的页面

有3种方案:
1、建议采用DJANGO后端来生成html页面的方式(本次采用该方案,快速暴力)
2、返回给vue前端,vue页面拿到支付宝的响应url中的参数,往Django后端完成数据保存并返回数据,
再根据返回的数据重新加载页面。
3、通过支付宝来生成支付页面图片(参考支付宝页面生成API开发文档),这样无需进行页面跳转,即可在同一页面完成数据的加载。

  url(r'^index/', TemplateView.as_view(template_name="index.html"), name="index"),

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>首页</title></head><body><div id="app"></div><script type="text/javascript" src="/static/index.entry.js"></script></body>
</html>

更多推荐

【Vue+Django REST framework实战】第9章—— 购物车、订单管理和支付功能

本文发布于:2024-02-27 00:34:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1704564.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:购物车   实战   订单管理   功能   Django

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!