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
相关产品推荐
相关产品推荐

