繁体   English   中英

检查queryset在Django中是否为空

[英]Check queryset is empty in Django

假设我有一段代码,例如:

class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        all_entries = Choice.objects.all()

        if not all_entries:
            return Question.objects.filter(pub_date__lte=timezone.now())

我试图从一个问题中获取所有选择,如果没有可用的返回404。 但是我只设法实现了其中一部分并得到了错误:

'NoneType'对象没有属性'filter'

这是从Django教程的最底部提到的

例如,无选择地在网站上发布问题是很愚蠢的。 因此,我们的观点可以对此进行检查,并排除此类问题。

我要去哪里错了?

编辑:

我将引用“ all_entries”的代码更改为:

all_entries = Choice.objects.all().count()

if all_entries > 0:
    return Question.objects.filter(pub_date__lte=timezone.now())

但这只是返回所有问题,无论他们是否有选择...

型号

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):              # __unicode__ on Python 2
       return self.question_text

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'


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

    def __str__(self):              # __unicode__ on Python 2
        return self.choice_text

编辑cms_mgr

基本上,我想检查与指定问题相关的选项数量是否为空。 当我转到此链接时http://127.0.0.1:8000/polls/3/我想从ID('3')中获取问题,并检查其包含的选择数量。

当且仅当它们具有相关选择时,获取所有问题的一种方法是获取Choices列表,而不是问题,然后根据这些问题评估您的查询。 例如:

Question.objects.filter(pk__in=[x.question.pk for x in Choice.objects.all()])

方括号内的位是列表理解 列表推导非常有用,并且值得了解。 在列表上方的代码中,理解力将首先评估。 基本上说的是“对于Choice.objects.all()每个x ,将x.pk放入此列表中”。 然后查询集将返回存在至少一个相关Choice每个Question

如果您想要的是每个QuestionChoices ,那么它们已经可供您使用。 对于Question任何实例,我们将其称为q ,您可以使用q.choice_set.all()获得与之关联的Choices ,如果不存在则返回空值。

要实现:首先更改您的DetailView的名称,以避免与通用名称混淆。 我们称它为QuestionDetailView 添加一个context_object_name以使您的模板以后更易读。 不要修改默认查询集以排除未发布的问题,因为正确的方法是使用模型管理器

class QuestionDetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'
    context_object_name = 'question'

在您用于该视图的模板中,问题的相关选择已经可以通过{% for choice in question.choice_set.all %} 这个question之所以被称为,是因为我们给它提供了一个context_object_name因此您可以使用任何您喜欢的名称。 请注意,模板中的all都不需要()

如果您需要对选择进行其他处理,然后再将其返回到模板,则可以在视图中进行选择。 因此,在您的QuestionDetailView您可以添加:

def get_context_data(self, **kwargs):
    # call the base implementation to get original context
    context = super(DetailView, self).get_context_data(**kwargs)
    context['choices'] = self.object.choice_set.all() # your question's choice set, to manipulate
                                                      # as you see fit
    return context

我会解释这里发生了什么。 这为视图返回的模板添加了额外的上下文。 我编写的代码将仅返回所有问题的选择,因此不会添加到已有的内容中,但是您可以执行自己喜欢的其他任何操作。 然后,修改后的选择集将在您的模板中作为choices可用,因此您可以在{% for choice in choices %}执行{% for choice in choices %}

无论采用哪种方式选择一个空的选择集都是可能的,并且可以轻松地迎合它(例如,模板中的{% if choices %}{% if question.choice_set.count %} )。 您可能想要比404更优雅地处理任何空查询集,因为您实际上并不希望将用户定向到错误页面以得到可预测的结果,例如空查询集。

如果all_entries 不为空,则不返回任何内容。 如果函数未明确返回值,则Python返回None

您尝试做的事情并不像看起来那样简单。 您必须按问题的查询选项集的数量来过滤问题,而不要检查选择项是否存在,然后返回问题。

您应该查看其他答案 ,看看如何通过注释来完成。

也许值得一提的是本系列后面的教程第7部分 ,从根本上提示了处理以下问题的正确方法。

例如,无选择地在网站上发布问题是很愚蠢的。 因此,我们的观点可以对此进行检查,并排除此类问题。

我认为解决此问题的最佳方法是首先避免创建“问题无选择”(假设没有人直接修改数据库)。 本教程教您如何修改管理站点页面,在该页面上,我们仅应允许管理员添加至少具有2个选择的Question。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM