Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#20795 closed Bug (invalid)

Weird queryset behaviour and count() method

Reported by: maa@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.5
Severity: Release blocker Keywords: count queryset
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I am having a really weird issue.
I have a queryset who returns nothing(even when it should) but still returns a value of one when using count() on it.

Here are the models:

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

And here is the part of the view who fails with IndexError:

if EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING).count() > 0:

contextnew_email = EmailChangeLog.objects.filter(user=self.request.user, state=EmailChangeLog.PENDING)[0].new_email

I ran the following lines after after putting a break point:

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

Is this a bug in django ? If not what is going on ?
I am using django 1.5.1
The same happens using manage shell_plus

I got rid of it by using a manager's method instead of the init function, if somehow this is not a bug can you please tell me what is going on and how can an empty queryset return a value greater than zero ?

Thanks.

Change History (4)

comment:1 by Collin Anderson, 11 years ago

What does your unicode method look like?
What does len(EmailChangeLog.objects.all()) return?
Do you have any other manager methods?
Could you narrow your problematic models down to the simplest form while still being able to reproduce the problem, and then share them somewhere?

comment:2 by maa@…, 11 years ago

I dont have a unicode method.
len(EmailChangeLog.objects.all()) fails with AttributeError: 'int' object has no attribute 'username'
traceback :

/home/maa/.virtualenvs/django_myproject/local/lib/python2.7/site-packages/django/db/models/query.pyc in __len__(self)
     88                 self._result_cache = list(self._iter)
     89             else:
---> 90                 self._result_cache = list(self.iterator())
     91         elif self._iter:
     92             self._result_cache.extend(self._iter)

/home/maa/.virtualenvs/django_myproject/local/lib/python2.7/site-packages/django/db/models/query.pyc in iterator(self)
    309                     obj = model_cls(**dict(zip(init_list, row_data)))
    310                 else:
--> 311                     obj = model(*row_data)
    312 
    313                 # Store the source database of the object

/home/maa/PycharmProjects/django_myproject/my_home/models.pyc in __init__(self, user, *args, **kwargs)
     41         super(EmailChangeLog, self).__init__(self, *args, **kwargs)
     42         salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
---> 43         username = user.username
     44         if isinstance(username, unicode):
     45             username = username.encode('utf-8')

AttributeError: 'int' object has no attribute 'username'

My manager has only one method and did n"t use it.
I have only one model and I already gave my 'models.py' code here is a pastebin : http://pastebin.com/0qSkeveT
Their is no view code involved, the same weird behaviour happens with the 'manage.py shell_plus' command.
Also I am using postgresql 8.4.17 on ubuntu 12.04 LTS, thanks for your support.

comment:3 by Anssi Kääriäinen, 11 years ago

Resolution: invalid
Status: newclosed

There seems to be two things going on:

1) You have overriden the model's init in a way that is incompatible to what Django expects. You can't add user arg to it, you might be able to use user kwarg instead. Basically, the signature must be *args, **kwargs, or Django will not be able to load your models back from DB.
2) There is a bug in Python (IIRC) that causes errors inside list(qs) to swallow the error and return empty list. This is fixed in 1.6.

So, marking this as invalid.

comment:4 by anonymous, 11 years ago

thanks for the update.

Note: See TracTickets for help on using tickets.
Back to Top