Django循环中获取唯一Question值:distinct()失效求助
解决Django中Question去重问题
问题分析
你当前的写法里,distinct() 完全起不到全局去重的作用——因为每次循环都是单独查询当前主题下的问题,且仅取第一个随机结果,既没有排除之前已经选中的问题,distinct() 也只是对单次查询的结果去重(而单次查询的结果本身就是唯一的Question ID,所以这个调用毫无意义)。最终导致同一个Question可能被多次选中加入questions_list。
解决方案
核心思路是记录已选中的Question ID,每次查询时排除这些ID,同时批量获取每个主题需要的问题数量,避免循环多次查询提升效率:
subject = QuestionSubject.objects.get(id=request.POST.get('subject')) question_topics = QuestionTopic.objects.filter(question_subject=subject) questions_list = [] selected_ids = set() # 用集合存已选ID,查询排除时效率更高 for topic in question_topics: need_count = topic.exam_questions_num if not need_count: continue # 如果不需要取该主题的问题,直接跳过 # 查询当前主题下、未被选中的问题,随机排序后取指定数量 selected_questions = Question.objects.filter( question_subject=subject, question_topic=topic, id__notin=selected_ids ).order_by('?')[:need_count].values_list('id', flat=True) # 将结果加入列表和已选集合 questions_list.extend(selected_questions) selected_ids.update(selected_questions)
关键说明
- 使用
set存储已选ID:集合的查询效率远高于列表,用id__notin=selected_ids排除已选问题时性能更好。 - 批量获取问题:直接通过切片
[:need_count]一次获取需要的数量,替代循环多次查询,减少数据库交互次数。 - 处理边界情况:如果某个主题下的可用问题数量少于
exam_questions_num,切片会自动取所有剩余问题,不会抛出异常。
为什么原代码的distinct()无效?
原代码中distinct()作用于单次查询的结果集,但Question的id是主键本身就唯一,单次查询的结果集里不会有重复ID,所以这个调用完全多余。而且每次查询没有排除之前选中的ID,所以重复选中同一个Question的概率很高。
内容的提问来源于stack exchange,提问作者Giorgio Scarso
相关产品推荐
相关产品推荐

