使用Django Rest Framework ViewSet遇404错误,需URL参数过滤查询集
解决DRF ViewSet中URL参数过滤查询集的404问题
嘿,刚上手DRF遇到这种问题太正常了,咱们一步步拆解排查,搞定它~
首先,先明确几个核心点:404错误要么是路由不匹配,要么是请求的资源确实不存在(但用URL参数过滤列表的话,正常应该返回空数组而非404,所以大概率是路由或过滤逻辑的问题)。
第一步:补全正确的路由配置
你提到用了DefaultRouter,先确保你的urls.py是这么写的(别漏了关键的注册和include步骤):
from django.urls import path, include from rest_framework.routers import DefaultRouter from .views import OffreViewSet # 替换成你实际的ViewSet路径 router = DefaultRouter() # 注册Offre的ViewSet,路由前缀设为offres router.register(r'offres', OffreViewSet) urlpatterns = [ # 把router生成的路由包含进来 path('', include(router.urls)), ]
这一步错了的话,哪怕过滤逻辑对了,访问的路径不对直接就404了。
第二步:在ViewSet中实现URL参数过滤
要通过URL查询参数(比如?secteur=IT)过滤查询集,最直观的方式是重写get_queryset方法,手动处理参数。先看完整的ViewSet代码:
from rest_framework import viewsets from .models import Offre from .serializers import OffreSerializer # 别忘了写对应的序列化器! class OffreViewSet(viewsets.ModelViewSet): # 基础查询集 queryset = Offre.objects.all() serializer_class = OffreSerializer def get_queryset(self): # 先拿到父类的基础查询集 queryset = super().get_queryset() # 从URL查询参数中获取secteur值 secteur_param = self.request.query_params.get('secteur', None) if secteur_param: # 过滤出secteur匹配的记录 queryset = queryset.filter(secteur=secteur_param) # 如果你还想支持按招聘者ID过滤,同样的逻辑 recruteur_id = self.request.query_params.get('idRecruteur', None) if recruteur_id: # 外键过滤用_id后缀更高效,也可以用idRecruteur=Recruteur.objects.get(id=recruteur_id) queryset = queryset.filter(idRecruteur_id=recruteur_id) return queryset
为什么会出现404?常见坑点
- 请求路径写错了:
正确的过滤请求应该是GET /offres/?secteur=IT(参数在?后面),如果你写成/offres/secteur=IT/或者/offres/IT/,路由会认为你在访问某个详情资源(比如主键为IT的Offre),自然返回404。 - 参数名拼写错误:
比如你在URL里传的是sector=IT,但代码里写的是secteur,过滤后查询集为空,但列表视图会返回空数组,不会404——除非你误访问了详情端点(比如/offres/123/但123不存在)。 - ViewSet关联错误:
如果serializer_class没定义或者写错,可能导致序列化错误,但一般是500而非404;如果queryset没设置,DRF也会报错,但也不是404。
进阶:用django-filter简化过滤
如果需要更复杂的过滤逻辑(比如模糊匹配、范围过滤),推荐用django-filter库,配置更省心:
- 先安装:
pip install django-filter - 在
settings.py中添加配置:
INSTALLED_APPS = [ ... 'django_filters', ] REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] }
- 修改ViewSet,直接指定可过滤字段:
class OffreViewSet(viewsets.ModelViewSet): queryset = Offre.objects.all() serializer_class = OffreSerializer # 指定允许过滤的字段,直接用?secteur=IT&idRecruteur=1即可过滤 filter_fields = ['secteur', 'idRecruteur']
最后排查步骤
- 确认请求URL是
http://localhost:8000/offres/?secteur=你的行业(替换成你数据库中存在的secteur值) - 检查
get_queryset里的参数名和URL中的参数名完全一致 - 打开DRF的API界面(比如
/offres/),直接在界面上输入参数测试,避免手动拼URL出错
内容的提问来源于stack exchange,提问作者M1rwen
相关产品推荐
相关产品推荐

