You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于条件拼接Queryset?展示含答案的Question及未答提示的最优实现方案

最佳实现方案(基于Django场景)

这其实是项目里很常见的需求,我来分享下兼顾性能和可读性的最优思路:

1. 先确保模型关系正确(基础前提)

首先得保证你的Answer模型已经正确关联了Question和用户,还要加个唯一约束避免用户重复回答同一问题:

from django.db import models
from django.contrib.auth.models import User

class Question(models.Model):
    category = models.ForeignKey('Category', on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    content = models.TextField()
    # 其他业务字段...

class Answer(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='answers')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        # 关键:确保一个用户对同一个问题只能有一条回答
        unique_together = ('question', 'user')

2. 视图层优化查询(核心性能点)

绝对不要在模板里循环问题时每次都查数据库找回答——这会触发N+1查询,性能拉胯。我们可以批量获取所有需要的回答,再构建一个问题ID到回答的映射字典:

from django.shortcuts import get_object_or_404, render

def category_questions(request, category_id):
    # 获取目标分类下的所有问题
    target_category = get_object_or_404(Category, id=category_id)
    questions = Question.objects.filter(category=target_category).order_by('id')

    # 获取当前用户针对这些问题的所有回答,提前关联问题避免额外查询
    user_answers = Answer.objects.filter(
        user=request.user,
        question__in=questions
    ).select_related('question')

    # 构建映射:用问题ID当key,直接对应到回答对象
    answer_map = {ans.question_id: ans for ans in user_answers}

    # 把数据传给模板
    return render(request, 'question_list.html', {
        'questions': questions,
        'answer_map': answer_map,
        'category': target_category
    })

3. 模板层渲染展示

遍历问题时,通过映射字典快速匹配回答,没有回答就显示警告。这里可以自定义个小过滤器让模板写法更简洁:

先在你的app下创建templatetags/custom_filters.py:

from django import template

register = template.Library()

@register.filter(name='get_answer')
def get_answer(answer_map, question_id):
    return answer_map.get(question_id)

然后在模板里使用:

{% load custom_filters %}

<h1>{{ category.name }} 分类问题列表</h1>

{% for question in questions %}
    <div class="question-card">
        <h3>{{ question.title }}</h3>
        <p class="question-content">{{ question.content }}</p>

        {% with answer=answer_map|get_answer:question.id %}
            {% if answer %}
                <div class="answer-block">
                    <h4>您的回答:</h4>
                    <p>{{ answer.content }}</p>
                    <small>回答时间:{{ answer.created_at|date:"Y-m-d H:i" }}</small>
                </div>
            {% else %}
                <div class="alert-warning">
                    ⚠️ <strong>提醒:</strong>您尚未回答此问题,请及时完成!
                </div>
            {% endif %}
        {% endwith %}
    </div>
{% endfor %}

如果不想自定义过滤器,也可以直接用字典键判断:

{% for question in questions %}
    <div class="question-card">
        <h3>{{ question.title }}</h3>
        <p class="question-content">{{ question.content }}</p>

        {% if question.id in answer_map %}
            <div class="answer-block">
                <h4>您的回答:</h4>
                <p>{{ answer_map.question.id.content }}</p>
                <small>回答时间:{{ answer_map.question.id.created_at|date:"Y-m-d H:i" }}</small>
            </div>
        {% else %}
            <div class="alert-warning">
                ⚠️ <strong>提醒:</strong>您尚未回答此问题,请及时完成!
            </div>
        {% endif %}
    </div>
{% endfor %}

为什么这是最优方案?

  • 性能拉满:只执行2次数据库查询(一次查问题,一次查用户回答),彻底避免N+1问题,数据量大时优势明显。
  • 逻辑清晰:映射字典直接关联问题和回答,模板层逻辑简单易懂。
  • 扩展性强:后续要加回答编辑、删除功能,直接操作answer对象即可。

内容的提问来源于stack exchange,提问作者Hari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:06:33