Django集成Redis 6.2拍卖出价时Product触发类型报错与连锁异常
报错根因定位
- 最先触发的
Invalid input of type: 'Product'是核心源头问题:redis-py 作为Redis 6.2的官方Python客户端,对传入的Redis key、hash field、存储值有严格类型要求,仅支持bytes、字符串、整数、浮点数格式的入参。代码里直接把Product.objects.get()拿到的ORM模型实例当Redis key传值,客户端没法把自定义的模型对象序列化到Redis的存储格式里,直接抛出类型校验异常。 - 后续出现的
argument of type 'WindowsPath' is not iterable、TypeError: 'NoneType' object is not subscriptable都是连锁触发的次生错误:第一步的类型异常没有被捕获,Django的请求处理流程被强行中断,后续的静态文件解析、消息框架渲染等中间件逻辑拿不到正常的上下文数据,才会抛出这些和拍卖业务本身无关的报错,不需要单独排查Path相关的代码,把核心的Redis传参问题修完,这些连锁错误会自动消失。
代码中的具体问题
- 非法传值:除了把Product对象直接当Redis key的问题,代码里
user_key = request.user拿到的是User模型实例,后续redis_instance.hset(product_key, user_key, bid_price)把User对象当hash field名传,同样会触发同类类型报错,只是第一步的Product传值异常先触发,没走到这步而已。 - 逻辑bug:从Redis读取的最高出价是字符串类型,直接把用户提交的bid_price(同样是字符串)和读出来的值做大小比较,会出现字符串排序的逻辑错误——比如字符串形式的"100"会被判定比"20"大,和实际数值大小完全不符。
- 框架使用错误:调用
messages.info()的时候漏传了必须的第一个request参数,Django消息框架要求必须传入当前请求对象,否则在页面渲染阶段会触发报错。 - 逻辑疏漏:第一次初始化最高出价的分支里,没有做任何出价校验就直接写入值,后续的比价逻辑完全没覆盖这个初始写入的场景。
修正后的核心实现
所有传给Redis的key、field全部替换为固定格式的字符串,全程用可识别的数值类型做比价逻辑:
elif request.method == 'POST': bid_price = request.POST.get('bid') retrieve_product_id = request.POST.get('product.id') # 先查询对应商品对象 product_obj = Product.objects.get(id=retrieve_product_id) minimum_price = float(product_obj.base_price) bid_float = float(bid_price) # 构造符合类型要求的Redis key,带业务前缀避免key空间冲突 redis_product_key = f"auction:product:{product_obj.id}" if bid_float < minimum_price: return HttpResponse('Your bid is lower than minimum price') # 读取当前已存的最高出价 current_highest = redis_instance.hget(redis_product_key, "highest_bid") if not current_highest: # 首次出价场景,直接写入当前值 redis_instance.hset(redis_product_key, "highest_bid", bid_float) # 用用户ID构造合法的hash field,不要传整个User对象 redis_instance.hset(redis_product_key, f"user_bid:{request.user.id}", bid_float) # 注意messages调用必须传request作为第一个参数 messages.info(request, 'Your bid was successfully processed') return HttpResponse('successfully uploaded') current_highest_float = float(current_highest) if bid_float > current_highest_float: redis_instance.hset(redis_product_key, f"user_bid:{request.user.id}", bid_float) redis_instance.hset(redis_product_key, "highest_bid", bid_float) messages.info(request, 'Your bid was successfully processed') return HttpResponse('successfully uploaded') else: return HttpResponse('Your bid is lower than current highest bid')
内容的提问来源于stack exchange,提问作者Non_specificato
相关产品推荐
相关产品推荐

