零基础入门python42:订单权限与用户数据隔离 零基础入门python42订单权限与用户数据隔离一、上一篇课后练习讲解购物车只能在订单事务提交成功后清空库存不足时应保留购物车方便用户修改数量。清空动作可以在 Service 成功返回后执行。上一篇课后练习完整答案上一篇练习的要求已落实到下面完整文件先运行项目测试再用 curl 对照状态码和数据库持久化结果答案要点下单 API 只接受已认证用户服务层扣库存并返回 409事务成功后才清 Session重复幂等键不产生新订单。文件shop/api.py完整参考答案文件完整文件shop/api.pyfromrest_framework.viewsimportAPIViewfromrest_framework.responseimportResponsefromrest_framework.permissionsimportIsAuthenticatedfrom.servicesimportplace_orderclassOrderCreate(APIView):permission_classes[IsAuthenticated]defpost(self,request):try:orderplace_order(request.user,request.data[items])except(KeyError,ValueError)asexc:returnResponse({error:str(exc)},status409)returnResponse({id:order.id,total:str(order.total)},status201)完整参考答案文件本篇对应的交付源码完整文件django-shop/shop/views.pyfromrest_frameworkimportgenerics,permissions,status,viewsetsfromrest_framework.responseimportResponsefrom.modelsimportCategory,Order,Productfrom.serializersimportCategorySerializer,CheckoutSerializer,OrderSerializer,ProductSerializerfrom.servicesimportcreate_orderclassCategoryViewSet(viewsets.ReadOnlyModelViewSet):querysetCategory.objects.order_by(name)serializer_classCategorySerializerclassProductViewSet(viewsets.ReadOnlyModelViewSet):serializer_classProductSerializerdefget_queryset(self):queryProduct.objects.filter(is_activeTrue).select_related(category)ifcategory:self.request.query_params.get(category):queryquery.filter(category_idcategory)ifkeyword:self.request.query_params.get(q):queryquery.filter(name__icontainskeyword)returnquery.order_by(-created_at)classCheckoutView(generics.GenericAPIView):permission_classes(permissions.IsAuthenticated,)serializer_classCheckoutSerializerdefpost(self,request):serializerself.get_serializer(datarequest.data)serializer.is_valid(raise_exceptionTrue)ordercreate_order(request.user,serializer.validated_data[items])returnResponse(OrderSerializer(order).data,status201)classMyOrderViewSet(viewsets.ReadOnlyModelViewSet):permission_classes(permissions.IsAuthenticated,)serializer_classOrderSerializerdefget_queryset(self):returnOrder.objects.filter(userself.request.user).prefetch_related(items).order_by(-id)classCartView(generics.GenericAPIView):defget(self,request):returnResponse(request.session.get(cart,{}))defpost(self,request):productgenerics.get_object_or_404(Product,idrequest.data.get(product_id),is_activeTrue)quantityint(request.data.get(quantity,1))ifquantity1orquantityproduct.stock:returnResponse({message:数量必须大于0且不能超过库存},statusstatus.HTTP_400_BAD_REQUEST)cartrequest.session.setdefault(cart,{})cart[str(product.id)]quantity request.session.modifiedTruereturnResponse(cart,statusstatus.HTTP_201_CREATED)defdelete(self,request):cartrequest.session.get(cart,{})cart.pop(str(request.data.get(product_id)),None)request.session.modifiedTruereturnResponse(cart)验收命令python -m pytest -qDjango 项目使用 python manage.py test。预期测试通过若失败先检查迁移、配置和事务回滚。二、本篇完成什么实现“我的订单”列表和详情确保任何用户只能看到自己的订单和订单项。三、查询集隔离classMyOrderViewSet(viewsets.ReadOnlyModelViewSet):permission_classes(permissions.IsAuthenticated,)serializer_classOrderSerializerdefget_queryset(self):return(Order.objects.filter(userself.request.user).prefetch_related(items).order_by(-id))prefetch_related适合反向一对多订单项select_related适合单值外键。查询级隔离比响应前删除字段更安全因为不属于用户的数据根本不会被加载。四、验收用户 A 下单后能看到订单用户 B 登录后列表为空请求 A 的详情返回 404未登录返回 403。课后练习增加管理员查看全部订单的独立接口不要放宽普通用户 ViewSet。项目增量订单权限和用户隔离普通用户只能读取自己的订单管理员可以查看全部但不能篡改支付结果。ViewSet 的 queryset 必须基于 request.user 构造而不是序列化后再过滤。defget_queryset(self):ifself.request.user.is_staff:returnOrder.objects.all()returnOrder.objects.filter(userself.request.user)对象级权限还要保护订单详情、取消和物流接口猜测其他订单 id 应返回 404 或 403不能泄露订单是否存在。课后练习写管理员和普通用户两组测试。五、上一篇练习讲解失败下单不能清空购物车清空购物车必须放在place_order成功返回之后若库存不足抛出异常视图直接返回 409Session 原样保留用户可以调整数量后再次提交。幂等键重试返回旧订单时也可以清空已经确认的购物车但要记录这是重试而不是新下单。六、ViewSet 的 queryset 是第一道权限classOrderViewSet(viewsets.ReadOnlyModelViewSet):serializer_classOrderSerializer permission_classes[IsAuthenticated]defget_queryset(self):baseOrder.objects.select_related(user).prefetch_related(items)ifself.request.user.is_staff:returnbase.order_by(-created_at)returnbase.filter(userself.request.user).order_by(-created_at)管理员分支只扩大读取范围支付状态修改仍应放到专门的 staff action并检查状态机。不要先Order.objects.all()再在序列化器里隐藏字段那会把越权对象加载到内存并可能泄露数量统计。七、对象权限和状态变更action(detailTrue,methods[post])defcancel(self,request,pkNone):orderself.get_object()# 已经过 get_queryset 的用户过滤iforder.status!pending:returnResponse({error:cannot_cancel},status409)order.statuscancelledorder.save(update_fields[status])returnResponse(OrderSerializer(order).data)self.get_object()必须保留不能改成Order.objects.get(pkpk)后者会绕过用户过滤。订单详情使用prefetch_related(items)避免展示订单项时 N1。八、验收和排错python manage.py test shop.tests.OrderPermissionTests-v 2用户 A 下单后B 的列表为空、详情返回 404staff 列表能看到两者。若 B 得到 200检查get_queryset是否返回了Order.objects.all()若取消已支付订单成功检查状态判断是否写在 serializer 而不是 service避免其他入口绕过。九、本篇练习增加 staff 专用“发货” action只允许paid - shipped普通用户调用返回 403。写管理员和普通用户两组测试并确保查询订单项不会产生 N1。下一篇会用接口测试覆盖库存边界和事务失败。十、权限检查的反例实验临时把get_queryset改成Order.objects.all()用用户 B 请求 A 的详情测试应立即失败恢复过滤后再运行。这个小实验比背“对象级权限”更能说明问题权限不是序列化器里隐藏几个字段而是从数据库查询开始就减少可见对象。删除或取消接口同样必须调用self.get_object()不要重新按主键查询。管理员导出订单时也要做审计记录导出人、过滤条件和行数下载链接设置过期时间。权限不仅发生在 ViewSetCelery 任务和管理命令也要显式传入操作者或服务账号不能因为“后台代码可信”就跳过所有权检查。本篇结束完整模块文件下面是交付项目中真实存在的完整文件 django-shop/shop/views.py。它覆盖本篇新增逻辑以及前文已经完成的依赖代码复制单个函数会丢失上下文因此这里提供整份文件。fromrest_frameworkimportgenerics,permissions,status,viewsetsfromrest_framework.responseimportResponsefrom.modelsimportCategory,Order,Productfrom.serializersimportCategorySerializer,CheckoutSerializer,OrderSerializer,ProductSerializerfrom.servicesimportcreate_orderclassCategoryViewSet(viewsets.ReadOnlyModelViewSet):querysetCategory.objects.order_by(name)serializer_classCategorySerializerclassProductViewSet(viewsets.ReadOnlyModelViewSet):serializer_classProductSerializerdefget_queryset(self):queryProduct.objects.filter(is_activeTrue).select_related(category)ifcategory:self.request.query_params.get(category):queryquery.filter(category_idcategory)ifkeyword:self.request.query_params.get(q):queryquery.filter(name__icontainskeyword)returnquery.order_by(-created_at)classCheckoutView(generics.GenericAPIView):permission_classes(permissions.IsAuthenticated,)serializer_classCheckoutSerializerdefpost(self,request):serializerself.get_serializer(datarequest.data)serializer.is_valid(raise_exceptionTrue)ordercreate_order(request.user,serializer.validated_data[items])returnResponse(OrderSerializer(order).data,status201)classMyOrderViewSet(viewsets.ReadOnlyModelViewSet):permission_classes(permissions.IsAuthenticated,)serializer_classOrderSerializerdefget_queryset(self):returnOrder.objects.filter(userself.request.user).prefetch_related(items).order_by(-id)classCartView(generics.GenericAPIView):defget(self,request):returnResponse(request.session.get(cart,{}))defpost(self,request):productgenerics.get_object_or_404(Product,idrequest.data.get(product_id),is_activeTrue)quantityint(request.data.get(quantity,1))ifquantity1orquantityproduct.stock:returnResponse({message:数量必须大于0且不能超过库存},statusstatus.HTTP_400_BAD_REQUEST)cartrequest.session.setdefault(cart,{})cart[str(product.id)]quantity request.session.modifiedTruereturnResponse(cart,statusstatus.HTTP_201_CREATED)defdelete(self,request):cartrequest.session.get(cart,{})cart.pop(str(request.data.get(product_id)),None)request.session.modifiedTruereturnResponse(cart)

相关新闻

最新新闻

多智能体自发协调失控?关键节点的人类介入机制

多智能体自发协调失控?关键节点的人类介入机制

前一阵子在项目里调一个多智能体协作流程,我让三个智能体分别负责数据抽取、格式转换和报告生成。刚开始跑的时候,每个智能体看起来都尽职尽责:抽取的智能体说抽到了字段,转换的智能体说格式已对齐,报告智能体输出了一…

2026/9/2 8:53:15
2026年GEO服务商怎么选?GEO服务商TOP10企业评估与测评

2026年GEO服务商怎么选?GEO服务商TOP10企业评估与测评

开篇导读什么是GEO服务商?GEO,即生成式引擎优化(Generative Engine Optimization),其服务商是一类专门帮助企业在人工智能大模型生态中提升数字可见度与认知权重的专业机构。与传统的SEO侧重于让用户在搜索中“找到”品…

2026/9/2 8:53:15
Matlab实现f-k域地震数据处理:原理、掩膜设计与实战避坑

Matlab实现f-k域地震数据处理:原理、掩膜设计与实战避坑

简介:本资源是一份面向地震学研究者与地球物理方向MATLAB初学者的F-K(傅里叶-克尔斯特拉)谱分析工具包,用于高效提取地震序列的频散特征并反演地下结构。压缩包仅含1个核心MATLAB脚本文件(fk.m)&#xff0c…

2026/9/2 8:53:15
Keras中Transformer因果掩码实现:解决时间序列预测信息泄露

Keras中Transformer因果掩码实现:解决时间序列预测信息泄露

在时间序列预测任务中,Transformer 架构因其强大的序列建模能力而备受关注。然而,直接将为自然语言处理设计的 Transformer 应用于时间序列预测,尤其是在多步预测场景下,会引入一个关键问题:信息泄露。未来的信息会“穿…

2026/9/2 8:53:15
Fast-WAM 深度解析:世界动作模型真的需要推理时的未来想象吗?

Fast-WAM 深度解析:世界动作模型真的需要推理时的未来想象吗?

1. 引言:从 VLA 到 WAM 的范式跃迁 在具身智能领域,如何让机器人理解物理世界并做出合理决策,一直是核心难题。过去两年,视觉-语言-动作模型(VLA)凭借大规模预训练和端到端推理的优势,成为机器…

2026/9/2 8:53:15
ADB脚本自动化:无需Root实现安卓设备批量控制与任务调度

ADB脚本自动化:无需Root实现安卓设备批量控制与任务调度

这次我们来看一个基于 ADB 调试的创意项目。ADB(Android Debug Bridge)是 Android 开发者最熟悉的工具之一,通常用于安装应用、抓取日志、调试系统。但它的能力远不止于此。通过一系列 ADB 命令的组合,我们可以实现很多自动化、批…

2026/9/2 8:48:15