Django中前两个视图正常,如何让过滤类视图生效?
解决Django过滤视图失效的问题
你的过滤功能失效主要有两个核心问题,逐一解决即可:
1. URL路由冲突
在urls.py中,你定义了两个完全相同的路径blogposts/:
- 第一个是
BlogPostListCreate视图 - 第二个是
BlogPostList过滤视图
Django的URL匹配是从上到下优先匹配第一个符合的路径,所以你的过滤视图永远不会被触发。
解决方法:
给过滤视图设置一个唯一的路径,比如blogposts/filter/,修改后的urls.py:
urlpatterns = [ path("blogposts/", views.BlogPostListCreate.as_view(), name="Blogpost-view-create"), path("blogposts/<int:pk>/", views.BlogPostRetrieveUpdateDestroy.as_view(), name="update"), path("blogposts/filter/", views.BlogPostList.as_view(), name="Filter"), ]
或者更优的方案:把过滤逻辑合并到已有的BlogPostListCreate视图中,避免重复的路径和视图,具体见下文的优化方案。
2. ORM过滤语法错误
在BlogPostList的get方法中,你写的过滤条件是title_icontains,但Django ORM的字段查找需要使用双下划线(__),正确的写法是title__icontains。单下划线会被Django识别为字段名的一部分,导致找不到对应字段而报错。
修复后的代码:
class BlogPostList(APIView): def get(self, request, format=None): title = request.query_params.get("title", "") if title: # 修复双下划线 blog_posts = BlogPost.objects.filter(title__icontains=title) else: blog_posts = BlogPost.objects.all() serializer = BlogPostSerializer(blog_posts, many=True) return Response(serializer.data, status=status.HTTP_200_OK)
优化方案(推荐)
既然BlogPostListCreate已经是列表视图,完全可以把过滤逻辑整合进去,不用单独写一个APIView,更符合DRF的设计习惯:
修改BlogPostListCreate类,重写get_queryset方法:
class BlogPostListCreate(generics.ListCreateAPIView): queryset = BlogPost.objects.all() serializer_class = BlogPostSerializer def get_queryset(self): # 获取基础查询集 queryset = super().get_queryset() # 从查询参数中获取title title = self.request.query_params.get("title", "") if title: # 添加过滤条件 queryset = queryset.filter(title__icontains=title) return queryset def delete(self, request, *args, **kwargs): BlogPost.objects.all().delete() return Response(status=status.HTTP_204_NO_CONTENT)
这样修改后,你可以直接访问原路径blogposts/?title=xxx来实现过滤,同时保留原有的创建、删除功能,还能删掉多余的BlogPostList视图和对应的URL路由,代码更简洁。
测试方法
不管用哪种方案,测试时直接在URL后添加查询参数即可,比如:
- 单独路径方案:
http://localhost:8000/blogposts/filter/?title=测试 - 整合方案:
http://localhost:8000/blogposts/?title=测试
内容的提问来源于stack exchange,提问作者Awm
相关产品推荐
相关产品推荐

