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

Django类视图如何传递pk参数到queryset过滤关联账户数据

问题根源

类视图中无法获取到账户pk参数、查询返回全量数据的核心原因有三点:

  • 你使用DefaultRouter注册IdentifierViewSet时,默认生成的列表接口路径为/api/portfolio/,路径中本身就没有携带账户主键参数
  • 路由器默认生成的详情路径/api/portfolio/<pk>/中的pk是Identifier模型自身的主键,并非关联的Account账户主键,直接取self.kwargs["pk"]要么取不到值,要么取错字段
  • 自定义的query_identifier_by_args函数内部直接从全量表查询数据,完全没有用到过滤后的结果集,就算路由参数取值正确,也不会生效
修复方案

1. 调整路由配置,显式传入账户主键参数

修改Urls.py中的路由注册逻辑,把账户pk作为路径参数加入接口前缀,注意参数名不要和模型默认的pk重名:

from . import views
from rest_framework.routers import DefaultRouter
from apps.portfolio.views import IdentifierViewSet

router = DefaultRouter()
# 显式在路径中加入account_pk参数,指定basename避免路由名生成冲突
router.register(r'account/(?P<account_pk>[^/.]+)/portfolio', IdentifierViewSet, basename='portfolio')


urlpatterns = [
    path('portfolios/', views.portfolios, name="portfolios"),
    path('portfolio/<str:pk>/', views.portfolio, name="portfolio"),
    path('api/', include(router.urls)),
]

调整后,Identifier列表接口的路径为/api/account/<账户pk>/portfolio/,路径中明确携带需要过滤的账户主键。

2. 修改数据查询逻辑,基于账户参数过滤

首先修改自定义的query_identifier_by_args函数,接收外部传入的已过滤基础结果集,不要直接查询全量表,同时修复参数缺省时的报错问题:

def query_identifier_by_args(base_queryset, **kwargs):
    draw = int(kwargs.get('draw', [0])[0])
    length = int(kwargs.get('length', [10])[0])
    start = int(kwargs.get('start', [0])[0])
    search_value = kwargs.get('search[value]', [''])[0]
    order_column = kwargs.get('order[0][column]', ['0'])[0]
    order = kwargs.get('order[0][dir]', ['asc'])[0]

    order_column = ORDER_COLUMN_CHOICES[order_column]
    # django orm 前加'-'代表倒序
    if order == 'desc':
        order_column = '-' + order_column

    queryset = base_queryset
    total = queryset.count()

    if search_value:
        queryset = queryset.filter(Q(id__icontains=search_value) |
                                        Q(code__icontains=search_value) |
                                        Q(code_type__icontains=search_value) |
                                        Q(created__icontains=search_value) |
                                        Q(updated__icontains=search_value) |
                                        Q(valid__icontains=search_value))

    count = queryset.count()
    queryset = queryset.order_by(order_column)[start:start + length]
    return {
        'items': queryset,
        'count': count,
        'total': total,
        'draw': draw
    }

再修改IdentifierViewSet类,移除硬编码的全量查询配置,在get_queryset方法中取出路由参数做过滤,同时在list方法中传入过滤后的基础结果集:

from django.shortcuts import get_object_or_404
from rest_framework import viewsets, status
from rest_framework.response import Response

class IdentifierViewSet(viewsets.ModelViewSet):
    # 移除硬编码的全量queryset配置,所有查询走get_queryset动态生成
    serializer_class = IdentifierSerializer
    authentication_classes = []

    def get_queryset(self):
        account_pk = self.kwargs.get("account_pk")
        # 校验账户是否存在,不存在直接返回404
        account = get_object_or_404(Account, id=account_pk)
        # 仅返回当前账户关联的Identifier数据
        return Identifier.objects.filter(account=account)

    def list(self, request, *args, **kwargs):
        try:
            # 先获取已经按账户过滤的基础结果集
            base_qs = self.get_queryset()
            identifier = query_identifier_by_args(base_qs, **request.query_params)
            serializer = IdentifierSerializer(identifier['items'], many=True)
            result = {
                'data': serializer.data,
                'draw': identifier['draw'],
                'recordsTotal': identifier['total'],
                'recordsFiltered': identifier['count']
            }
            return Response(result, status=status.HTTP_200_OK)
        except Exception as e:
            return Response(str(e), status=status.HTTP_404_NOT_FOUND)
可选替代方案

如果你不想修改现有路由结构,也可以把账户pk作为查询参数传递,前端请求时拼接为/api/portfolio/?account_pk=xxx,此时不需要修改路由,只需要把get_queryset中的取值逻辑改为从请求参数中获取即可:

def get_queryset(self):
    account_pk = self.request.query_params.get("account_pk")
    account = get_object_or_404(Account, id=account_pk)
    return Identifier.objects.filter(account=account)

这种方式实现更简单,但语义不如路径参数清晰,可根据业务场景选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:45:48