【发布时间】:2013-07-23 13:18:19
【问题描述】:
您可以猜到我遇到了一个非常奇怪的问题。 我有一个查询集,它什么都不返回(即使它应该返回)但在使用 count() 时仍然返回一个值。
以下是模型:
import hashlib
import random
from django.contrib.auth import get_user_model
from django.db import models
class EmailChangeLogManager(models.Manager):
def get_query_set(self):
return super(EmailChangeLogManager, self).get_query_set().filter(state=EmailChangeLog.PENDING)
def create_new_request(self, user):
request = self.model(user=user)
request.save()
return request
class EmailChangeLog(models.Model):
"""
logs the users requests to change their email
"""
PENDING = 0
CHANGED = 1
objects = EmailChangeLogManager()
user = models.ForeignKey(get_user_model())
token = models.CharField(max_length=40, primary_key=True) # primary key so it blows up in case of collision
state = models.SmallIntegerField()
new_email = models.CharField(max_length=30)
def __init__(self, user, * args, **kwargs):
super(EmailChangeLog, self).__init__(self, *args, **kwargs)
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
username = user.username
if isinstance(username, unicode):
username = username.encode('utf-8')
self.token = hashlib.sha1(salt+username).hexdigest()
self.user = user
self.state = EmailChangeLog.PENDING
下面是因 IndexError 而失败的视图部分:
if EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING).count() > 0:
context['new_email'] = EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING)[0].new_email
我在放置断点后运行了以下几行:
>>> EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING).count()
Out[1]: 1
>>> EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING)
Out[2]: []
>>> EmailChangeLog.objects.all().count()
Out[3]: 2
>>> EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING).count()
Out[4]: 1
>>> EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING)
Out[5]: []
>>> EmailChangeLog.objects.all().count()
Out[6]: 2
>>> EmailChangeLog.objects.all()
Out[7]: []
>>> EmailChangeLog.objects.filter(user=self.request.user)
Out[8]: []
>>> EmailChangeLog.objects.filter(state=EmailChangeLog.PENDING)
Out[9]: []
>>> EmailChangeLog.objects.filter()
Out[10]: []
>>> EmailChangeLog.objects.all()
Out[11]: []
>>> EmailChangeLog.objects.all().count()
Out[1]: 2
>>> EmailChangeLog.objects.all()
Out[3]: []
>>> EmailChangeLog.objects.all()
Out[5]: []
>>> EmailChangeLog.objects.all().count()
Out[6]: 2
>>> EmailChangeLog.objects.all().count()
Out[7]: 2
>>> az = EmailChangeLog.objects.all()
>>> az
Out[9]: []
>>> az.count()
Out[10]: 2
这是 django 中的错误吗?如果不是怎么回事?
PS:我使用的是 django 1.5.1
编辑:使用 manage shell_plus 也会发生同样的情况
【问题讨论】:
-
这不是错误。查询集对象的评估是惰性的——这意味着它不会获取查询集结果,除非它被使用。例如:即使
EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING)返回[]- 如果你这样做EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING)[:1]- 它会返回一个查询集,因为它在那个时间点被评估。 -
@karthikr:使用索引 0 访问它会引发 IndexError 异常,打印查询也应该消耗它吗?顺便说一句:[:0] 也一样
-
我的意思是
[:1]或[0] -
它因 IndexError 失败:列表索引超出范围
-
@maazza:当你做
objects.all()[0]之类的事情时,你会得到什么
标签: python django django-queryset django-1.5