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

如何用Django Rest Framework路由从URL捕获参数实现按用户ID列卡片

解决DRF路由实现按用户ID过滤卡片的问题

问题回顾

现有Card和User两个模型,Card通过外键owner关联User,需要实现一个视图:通过URL路径参数(如/cards/by-user-id/42/)返回指定ID用户的所有卡片。尝试用DRF的Router实现时,直接在路由前缀中写入<int:user_id>会被当作普通字符串,无法正确获取参数。

错误代码修正与解决方案

1. 基础代码修正

先修正原代码中的错误:

models.py(原代码无问题,保留)

from django.contrib.auth.models import User
from django.db import models

class Card(models.Model):
    owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)

serializers.py(原代码无问题,保留)

from rest_framework import serializers
from . import models

class CardSerializer(serializers.ModelSerializer):
    owner = serializers.StringRelatedField()

    class Meta:
        model = models.Card
        fields = ['owner', 'id']

2. 视图层实现自定义路由动作

DRF默认Router不支持在注册前缀中直接添加路径参数,需通过@action装饰器定义带参数的自定义动作,同时修正原视图中的错误:

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from . import models, serializers

class CardViewSet(viewsets.ModelViewSet):
    queryset = models.Card.objects.all()
    serializer_class = serializers.CardSerializer

    # 定义列表级自定义动作,url_path指定路径参数规则
    @action(detail=False, url_path='by-user-id/(?P<user_id>[0-9]+)')
    def by_user_id(self, request, user_id=None):
        # 过滤指定用户的卡片
        cards = models.Card.objects.filter(owner__id=user_id)
        serializer = self.get_serializer(cards, many=True)
        return Response(serializer.data)

3. 路由层正确配置Router

Router仅注册基础路径,自定义动作的路径由@action的参数指定:

from django.urls import path, include
from rest_framework import routers
from . import views

router = routers.SimpleRouter()
# 注册基础Card视图集,前缀为'cards'
router.register(r'cards', views.CardViewSet, basename='card')

urlpatterns = [
    path('', include(router.urls)),
]

配置完成后,访问/cards/by-user-id/42/即可正确返回ID为42的用户的所有卡片,user_id参数会自动传递到自定义动作方法中。

可选方案:嵌套路由(REST风格URL)

若希望URL结构更符合REST规范(如/users/42/cards/),可使用第三方包drf-nested-routers:

  1. 安装包:pip install drf-nested-routers
  2. 修改urls.py:
from django.urls import path, include
from rest_framework import routers
from rest_framework_nested import routers as nested_routers
from . import views

# 根路由注册User视图集
router = routers.SimpleRouter()
router.register(r'users', views.UserViewSet, basename='user')

# 基于用户路由嵌套卡片路由
user_router = nested_routers.NestedSimpleRouter(router, r'users', lookup='user')
user_router.register(r'cards', views.CardViewSet, basename='user-cards')

urlpatterns = [
    path('', include(router.urls)),
    path('', include(user_router.urls)),
]
  1. 修改CardViewSet的查询集方法:
def get_queryset(self):
    user_id = self.kwargs['user_id']
    return models.Card.objects.filter(owner__id=user_id)

此时访问/users/42/cards/即可获取该用户的所有卡片。

关键说明

DRF默认Router(SimpleRouter/DefaultRouter)为标准CRUD操作设计,无法直接在注册前缀中添加路径参数。通过@action装饰器可灵活定义自定义路由,或使用嵌套路由实现更规范的REST URL结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:20:48