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

Django:能否在filter()方法中使用_set筛选含Choice的Question?

解决Django polls应用IndexView仅返回含Choice的已发布问题

问题描述

在polls应用的IndexView(ListView子类)中,当前逻辑会返回最近5个已发布的Question,但其中包含没有任何Choice的Question,需要修改视图逻辑,只返回至少关联一个Choice的已发布Question。

现有代码

views.py中的IndexView

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """
        Return the last five published questions (not including those set to be
        published in the future).
        """
        return Question.objects.filter(
            pub_date__lte=timezone.now()
        ).order_by('-pub_date')[:5]

models.py中的模型定义

from django.db import models
import datetime
from django.utils import timezone

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text
    
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

修改方案

不能直接在filter()中使用_set对象(它是模型实例的属性,而非查询集层面的可用条件),可以通过Django的反向关联查询来过滤出关联至少一个Choice的Question,有两种高效实现方式:

方式1:使用__exists查询(推荐,性能更优)

利用choice__exists=True条件,通过EXISTS子查询判断Question是否存在关联的Choice,不会产生重复记录:

def get_queryset(self):
    """
    Return the last five published questions that have at least one choice
    (not including those set to be published in the future).
    """
    return Question.objects.filter(
        pub_date__lte=timezone.now(),
        choice__exists=True
    ).order_by('-pub_date')[:5]

方式2:使用__isnull查询+去重

通过choice__isnull=False筛选出存在关联Choice的Question,再用distinct()去重(因为一个Question有多个Choice时,会返回多条重复记录):

def get_queryset(self):
    """
    Return the last five published questions that have at least one choice
    (not including those set to be published in the future).
    """
    return Question.objects.filter(
        pub_date__lte=timezone.now(),
        choice__isnull=False
    ).distinct().order_by('-pub_date')[:5]

说明

  • 反向关联字段使用小写的模型名choice(对应Choice模型),Django会自动处理外键的反向关联查询
  • __exists查询会生成更高效的SQL语句(EXISTS子查询),无需额外去重操作,优先推荐使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:05:15