You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django API中按价格条件延迟重发创建请求?

解决方案

首先不建议在同步API视图中直接用time.sleep阻塞线程,这会拖慢服务的并发处理能力。如果一定要实现需求,可以通过递归调用自身+重试次数限制的方式完成,同时避免无限循环:

修改后的代码

from rest_framework import status
from rest_framework.response import Response
import time

class BuyProductViewset(viewsets.GenericViewSet, mixins.CreateModelMixin):
    serializer_class = UserproductSerializer
    queryset = Userproducts.objects.all()
    # 设定最大重试次数,防止无限递归耗尽资源
    MAX_RETRIES = 3

    def data_serialize(self, user_id, product_ID):
        data = {"user": user_id, "product": product_ID}
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return serializer, headers

    def create(self, request, *args, **kwargs):
        # 获取当前重试次数,默认0
        retry_count = kwargs.get('retry_count', 0)
        
        user_id = request.data["user_id"]
        product_id = request.data["product_id"]
        total = request.data["total"]
        upper_bound = request.data["upper_bound"]
        lower_bound = request.data["lower_bound"]
        
        # 模型类名修正为大写(Django规范),用last()替代reverse[:1].get()更简洁
        product = (
            Product.objects.filter(product_id=product_id)
            .order_by("timestamp")
            .last()
        )
        if not product:
            return Response({"error": "商品不存在"}, status=status.HTTP_404_NOT_FOUND)
            
        product_ID = product.id
        product_price = product.price
        product_availability = product.availability
        product_name = product.name

        if product_price >= int(lower_bound) and product_price <= int(upper_bound):
            serializer, headers = self.data_serialize(user_id, product_ID)
            # 原代码逻辑错误:创建新商品而非更新库存,这里改为update修正
            Product.objects.filter(id=product_ID).update(
                availability=product_availability - int(total)
            )
            return Response(
                serializer.data, status=status.HTTP_201_CREATED, headers=headers
            )
        else:
            # 超过重试上限则返回失败
            if retry_count >= self.MAX_RETRIES:
                return Response(
                    {"error": f"经过{self.MAX_RETRIES}次重试后,商品价格仍不在指定区间"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            # 延迟5秒后递归调用自身,重试次数+1
            time.sleep(5)
            return self.create(request, *args, **kwargs, retry_count=retry_count+1)

关键说明

  1. 重试次数控制:添加MAX_RETRIES常量,避免因价格持续不符合条件导致无限递归,保护服务器资源。
  2. 递归实现重发:在else分支中,延迟后调用自身的create方法,复用原请求数据并递增重试次数,完成重复请求逻辑。
  3. 代码修正与优化:
    • 遵循Django模型类名大写规范,修正原代码中的product为Product。
    • 替换reverse()[:1].get()为last(),简化最新商品查询逻辑。
    • 修正原代码中错误的库存更新逻辑:原代码会创建新商品实例,改为用update修改现有商品的库存数量。
    • 添加商品不存在的判断,避免get()抛出未捕获异常。

更优方案(推荐)

同步视图阻塞线程会严重影响服务并发能力,建议改用异步任务队列(如Celery)实现延迟重试:

  • 当价格不符合条件时,将请求数据存入任务队列,设置5秒延迟后执行。
  • 任务执行时重新检查价格,符合条件则创建Userproducts并更新库存,否则可继续重试或通知用户。

内容的提问来源于stack exchange,提问作者Menna Magdy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:48:38