Django如何使用用户存储的分类列表正确筛选Poller查询集?
问题根因
你存储用户选择的分类时,使用json.dumps()将分类列表序列化为了JSON字符串存入categories_selected字段,因此查询时取出的字段值不是Python列表,而是带方括号、引号的JSON格式字符串(比如你打印看到的['category_foo']实际是字符串"[\"category_foo\"]"),直接用这个字符串去匹配Category的category字段自然找不到结果,之前的Q对象写法失效也是同一个原因。
修复方案
取出分类配置后先做JSON反序列化,再执行查询即可:
import json def render_random_poller(request): if request.user.is_authenticated: # 获取用户的分类筛选配置,不存在则创建默认空配置 user_filter, _ = UserCategoryFilter.objects.get_or_create(user=request.user) # 反序列化JSON字符串得到分类名称列表 try: selected_categories = json.loads(user_filter.categories_selected) except json.JSONDecodeError: # 处理非法JSON的异常场景,默认返回空列表或全部分类 selected_categories = [] # 直接用分类名称列表查询Poller即可,不需要先查Category,减少一次数据库查询 qs_poller = Poller.objects.filter( poller_category__category__in=selected_categories ).order_by('-created_on')[:100] else: # 原有未登录逻辑 [...]
优化建议
当前用CharField存序列化JSON的方案兼容性和易用性都较差,可以直接改用Django原生的JSONField存储分类选择,无需手动做序列化/反序列化:
# 修改UserCategoryFilter模型字段 class UserCategoryFilter(models.Model): user = models.ForeignKey(Account, on_delete=models.CASCADE) # 替换原有CharField,默认值设为空列表 categories_selected = models.JSONField(default=list)
修改后保存分类的逻辑也可以简化,不需要调用json.dumps:
if filter_form.is_valid(): selection = filter_form.clean() # 直接存列表即可,不需要序列化 selected_list = [c.category for c in selection['choices']] UserCategoryFilter.objects.update_or_create( user=request.user, defaults={"categories_selected": selected_list} )
查询时也可以直接取字段值使用,不需要json.loads处理。
内容的提问来源于stack exchange,提问作者JSRB
相关产品推荐
相关产品推荐

