递归与树的写法-多种支付的设计-支付的接通-celery订单的回退实现
递归与树的写法
data:
data=[ {"cat_id":1,"name":"北京","parent_id":0}, {"cat_id":2,"name":"上海","parent_id":0}, {"cat_id":3,"name":"沙河","parent_id":1}, {"cat_id":4,"name":"sb镇","parent_id":3}, {"cat_id":5,"name":"昌平","parent_id":1}, {"cat_id":6,"name":"青浦","parent_id":2}, ]
#需求 ''' 问题: 我们数据不是有序的,但是我们要排序,并归类,把父集放在子集的前面,辈分等级通过level标明 '''
实现的方法
res=[] def get_son(data,level=0,parent_id=0,is_clear=True): if is_clear: res.clear() for item in data: if item['parent_id']==parent_id: item['level']=level res.append(item) get_son(data,level=level+1,parent_id=item['cat_id'],is_clear=False) return res
实现树状的等级分类
''' 问题: 因为前端,需要通过循环多少成来,展示多个等级 for item in data: print(item.name) for item1 in item.children item1.name 归档:我要把我的子集,都放在我的children列表里面 '''
def get_tree(data): lists=[] tree={} for i in data: tree[i['cat_id']]=i for item in data: if not item['parent_id']: lists.append(tree[item['cat_id']]) else: if "children" not in tree[item['parent_id']]: tree[item['parent_id']]['children']=[] tree[item['parent_id']]['children'].append(tree[item['cat_id']]) return lists
分析
多种支付的设计
例如实现微信或支付宝等支付接口的封装.
封装的支付接口方法
class Notity(APIView): def post(self,request,paymethon): pay_file = importlib.import_module(f"app01.Pay.{paymethon}") pay_class = getattr(pay_file, paymethon) data=pay_class().notity(request.data) if data['status']=="success": models.Order.objects.filter(order_id=data['order']).updata(pay_status=1)
pay.Alipay.py
class Alipay(): def pay(self): pass "order/notify/Alipay" def notity(self,data): data['shangcheng_id'] data['sucess'] if data['sucess']="00": return_data['stauts']="success" return_data['order_id'] = data['shangcheng_id'] return return_data else: pass
pay.Wxpay.py
import time from app01.wx import settings class Wxpay: def pay(self,order_data): self.order_id = order_data["order_id"] self.open_id = order_data['open_id'] self.ip = order_data['ip'] data_body = self.get_body_data() import requests url = "https://api.mch.weixin.qq.com/pay/unifiedorder" response = requests.post(url, data_body.encode("utf-8"), headers={'content-type': "application/xml"}) res_dict = self.xml_to_dic(response.content) timeStamp = str(int(time.time())) paySign = self.get_pay_sign(res_dict, timeStamp) data_dic = { 'timeStamp': timeStamp, 'nonceStr': res_dict['nonce_str'], 'package': f"prepay_id={res_dict['prepay_id']}", 'signType': 'MD5', "paySign": paySign, } return data_dic
支付的接通
from rest_framework.views import APIView from rest_framework.response import Response from django.core.cache import cache from app01 import models import hashlib,time from django.db import transaction from django import forms import importlib class OrderForm(forms.Form): phone = forms.CharField( error_messages={ "required": "手机号不能为空" }, # 调用Form组件中的验证器来校验手机号 # validators=[RegexValidator(r'1[1-9][0-9]{9}', '手机号格式不正确')], ) token = forms.CharField( error_messages={ "required": "token不能为空" }) province=forms.CharField( error_messages={ "required": "省份不能为空" }) city = forms.CharField(error_messages={ "required": "城市不能为空" }) county = forms.CharField(error_messages={ "required": "县/区不能为空" }) address = forms.CharField(error_messages={ "required": "详细地址不能为空" }) name = forms.CharField(error_messages={ "required": "姓名不能为空" }) class Creat(APIView): @transaction.atomic def post(self,request): param=request.data form_obj=OrderForm(param) if form_obj.is_valid() and param['buy_list']: if request.META.get("HTTP_X_FORWARDED_FOR"): host_ip = request.META["HTTP_X_FROWARDED_FOR"] else: host_ip = request.META["REMOTE_ADDR"] user_cache=cache.get(param['token']) if user_cache: openid=user_cache.split("&")[0] user_data=models.Wxuser.objects.filter(openid=openid).first() order_data = {"consignee_mobile": param['phone'], 'consignee_name': param['name'], 'wxuser_id': user_data.id, "memo": param['remark'], "consignee_area":f"{param['province']},{param['city']},{param['county']}", "consignee_address":param['address'] , } buy_list=param['buy_list'] goods_key=list(buy_list.keys()) all_product=models.Product.objects.filter(product_id__in=goods_key) order_data['order_id']=func.get_order_id() order_data['order_total']=0 order_data['quantity']=0 #开启库存 sid=transaction.savepoint() for product in all_product: product.product_id=str(product.product_id) order_data['order_total']+=product.price*buy_list[product.product_id] order_data['quantity']+=buy_list[product.product_id] #创建子订单 for i in range(3): #查询当前库存 stock=product.stock.quantity #当前减轻购买的数量,等于剩余的库存 new_stock=stock-buy_list[product.product_id] #判断库存是否足够 if new_stock<0: #回滚 transaction.savepoint_rollback(sid) #如果库存不住够,我们直接返回 return Response({"code":203,"msg":f"{product.name}库存不足"}) res=models.Stock.objects.filter(quantity=stock,stock_id=product.stock.stock_id).update(quantity=new_stock) if not res: if i==2: transaction.savepoint_rollback(sid) return Response({"code": 203, "msg": f"创建订单失败"}) else: continue else: break new_buy_count = product.buy_count + buy_list[product.product_id] models.Product.objects.filter(product_id=product.product_id).update(buy_count=new_buy_count) order_item_data={'order_id': order_data['order_id'], 'product_id': product.product_id, \ "name": product.name, "image": product.image, "price": product.price, \ "nums": buy_list[product.product_id], "brief": product.brief} models.Order_items.objects.create(**order_item_data) models.Order.objects.create(**order_data) pay_methon="Wxpay" try: pay_file=importlib.import_module(f"app01.Pay.{pay_methon}") pay_class=getattr(pay_file,pay_methon) order_data['open_id'] = openid order_data['ip']=host_ip data=pay_class().pay(order_data) except: transaction.savepoint_rollback(sid) return Response({"code": 200, "msg": "未知的支付方式" }) transaction.savepoint_commit(sid) func.add_task(order_data['order_id']) return Response({"code": 200, "msg": "ok" ,"data":data}) else: return Response({"code":202,"msg":"token已过期"}) else: return Response({"code":201,"msg":"缺少参数"})
celery实现订单的回退
简单的理解就是通过celery异步回调的机制,设置代码段过多少时间之后再去工作,把发起订单后为支付的数据信息返回。
task方法:
from pro_celery.celery import del_order def add_task(order_id,seconds=5): ctime = datetime.now() utc_ctime = datetime.utcfromtimestamp(ctime.timestamp()) from datetime import timedelta time_delay = timedelta(seconds=seconds) task_time = utc_ctime + time_delay result = del_order.apply_async(args=[order_id, ], eta=task_time)
celery.py方法的封装
import celery import time # broker='redis://127.0.0.1:6379/2' 不加密码 backend='redis://127.0.0.1:6379/1' broker='redis://127.0.0.1:6379/2' cel=celery.Celery('test',backend=backend,broker=broker) import os, sys import django BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # 定位到你的django根目录 # sys.path.append(os.path.join(BASE_DIR, "app01")) sys.path.append(os.path.abspath(BASE_DIR)) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wxshop.settings") django.setup() from django.db import transaction @cel.task @transaction.atomic def del_order(order_id): ''' 1 拿订单查询,订单号,是否支付,活跃 2 判断data是否有 :param order_id: :return: ''' from app01 import models data=models.Order.objects.filter(order_id=order_id,pay_status=0,status="active").first() if data: item_data=models.Order_items.objects.filter(order_id=order_id).values("product","nums") # [{product:1,nums:3}] # {1:3,2:1} all_product_dict = { k['product']:k['nums'] for k in item_data} all_product_id =list(all_product_dict.keys()) products_all=models.Product.objects.filter(product_id__in=all_product_id) sid=transaction.savepoint() for product in products_all: for i in range(3): stock=product.stock.quantity new_stock=stock+all_product_dict[product.product_id] new_buy_count=product.buy_count-all_product_dict[product.product_id] res=models.Stock.objects.filter(quantity=stock,stock_id=product.stock).update(quantity=new_stock) if not res: if i==2: from app01.comment import func transaction.savepoint_rollback(sid) func.add_task(order_id,1) return else: continue else: break models.Product.objects.filter(product_id=product.product_id).update(buy_count=new_buy_count) row=models.Order.objects.filter(order_id=order_id,pay_status=0).update(status="dead") if row: transaction.savepoint_commit(sid) else: transaction.savepoint_rollback(sid)
本文来自博客园,作者:游走De提莫,转载请注明原文链接:https://www.cnblogs.com/Gaimo/p/11830626.html