Django ViewSet如何选中指定Portfolio实例新增关联BuySell数据
报错根因
触发TypeError的核心原因是get_queryset方法返回值不符合DRF要求:self.request.user.portfolio是一对多反向关联生成的RelatedManager管理器对象,不是可被列表接口解析的QuerySet实例,框架尝试用该对象匹配查询条件时就会抛出类型错误。
问题1修复:正确获取查询集,支持指定Portfolio筛选
首先重写get_queryset方法,跨关联关系筛选当前用户有权限访问的所有买卖记录,支持通过查询参数指定单个投资组合:
def get_queryset(self): # 基础过滤:仅返回当前用户名下所有投资组合关联的买卖记录 queryset = BuySell.objects.filter(portfolio__user=self.request.user) # 支持前端传入portfolio_id参数,筛选指定投资组合下的记录 portfolio_id = self.request.query_params.get("portfolio_id") if portfolio_id: queryset = queryset.filter(portfolio_id=portfolio_id) return queryset
小提示:当前模型定义中Portfolio.user外键的related_name='portfolio'不符合命名规范,一对多反向关联建议用复数形式related_name='portfolios',后续调用user.portfolios.all()语义更清晰,避免开发时混淆。
问题2修复:向指定Portfolio新增BuySell记录
新增逻辑必须做权限校验,禁止前端越权向其他用户的投资组合写入数据,实现步骤如下:
- 先修改
BuySellSerializer,将portfolio字段设为只读,避免前端直接传值绕过校验:
class BuySellSerializer(serializers.ModelSerializer): class Meta: model = BuySell fields = "__all__" read_only_fields = ("portfolio",)
- 重写
create方法,先校验传入的投资组合归属,校验通过后再绑定保存:
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) share = serializer.validated_data["share"] # 校验必传参数 portfolio_id = request.data.get("portfolio_id") if not portfolio_id: return Response( {"error": "必须指定绑定的投资组合ID"}, status=status.HTTP_400_BAD_REQUEST ) # 校验投资组合归属,不存在或不属于当前用户直接返回404 target_portfolio = Portfolio.objects.filter( id=portfolio_id, user=request.user ).first() if not target_portfolio: return Response( {"error": "指定投资组合不存在或无操作权限"}, status=status.HTTP_404_NOT_FOUND ) # 保存时绑定校验通过的投资组合实例 serializer.save(portfolio=target_portfolio) return Response({"data": serializer.data}, status=status.HTTP_201_CREATED)
注意:不可直接使用前端传入的
portfolio_id关联保存,跳过归属校验会产生越权写入的安全漏洞。
内容的提问来源于stack exchange,提问作者Anjaan
相关产品推荐
相关产品推荐

