Django 2.0.2测试中QuerySet忽略国家过滤问题排查
排查DRF视图过滤条件失效问题的思路
这种情况我之前碰到过好几次,大概率是QuerySet的惰性求值特性或者过滤逻辑被意外覆盖导致的,咱们一步步来定位问题:
1. 先确认视图里的过滤逻辑真的生效了
先检查你的DRF视图get_queryset方法,有没有出现过滤后又被覆盖的情况?比如不小心用all()重新拉取了全量数据:
# 错误示例:过滤后又被覆盖 def get_queryset(self): # 这里明明加了过滤条件 queryset = super().get_queryset().filter(countries__id=6252001) # 但下面这行直接把之前的过滤结果冲掉了! queryset = AndroidOffer.objects.all() return queryset
建议在get_queryset末尾打印最终的SQL语句,对比和你在PostgreSQL控制台看到的是否一致:
def get_queryset(self): queryset = ... # 你的过滤逻辑 print(queryset.query) # 打印生成的SQL return queryset
2. 排查惰性求值的坑
Django QuerySet是惰性的——只有在实际取值(比如len()、遍历)时才会执行SQL。如果你的active_offers是类属性而不是动态生成的,那它会在类加载时就缓存全量数据,后续的过滤根本不会生效:
# 错误示例:类属性导致缓存全量数据 class AndroidOfferView(APIView): # 这里在项目启动时就执行了SQL,缓存了所有active的offer active_offers = AndroidOffer.objects.filter(is_active=True) def get(self, request): # 这里的过滤是在缓存的QuerySet上做的,但缓存已经是全量了 filtered = self.active_offers.filter(countries__id=6252001) return Response(serializer.data)
改成动态生成就好了:
def get_queryset(self): # 每次请求都重新生成QuerySet,确保过滤生效 return AndroidOffer.objects.filter(is_active=True).filter(countries__id=self.request.query_params.get('country_id'))
3. 检查多对多关系的过滤逻辑
你的过滤针对的是多对多中间表,先确认模型关系定义没问题:
class AndroidOffer(models.Model): countries = models.ManyToManyField(Country) # 确认是正向多对多
然后在普通TestCase里手动执行过滤,看结果是否符合预期:
from django.test import TestCase from yourapp.models import AndroidOffer class TestOfferFilter(TestCase): def test_filter(self): offers = AndroidOffer.objects.filter(countries__id=6252001) print(offers.query) # 和控制台的SQL对比 print(len(offers)) # 正常应该返回0
如果这个测试用例返回0,但APITestCase里返回4条,说明问题出在API请求的处理流程里——比如参数没传对、视图走了其他分支。
4. 检查APITestCase的请求参数
确认你在测试里传递的参数是正确的:
# 正确示例:GET请求参数要放在query_params里 response = self.client.get('/offers/', {'country_id': 6252001})
别搞错了参数名(比如视图里用country但你传了country_id),也别用request.data去取GET参数(GET参数在request.query_params里)。
5. 排查过滤后端/权限类的干扰
如果你用了自定义的FilterBackend或者权限类,会不会在处理请求时清空了过滤条件?比如某些权限类为了获取用户可访问数据,重新设置了queryset。可以临时注释掉这些组件,看过滤是否恢复正常。
内容的提问来源于stack exchange,提问作者artem
相关产品推荐
相关产品推荐

