#12687 closed (fixed)
Using exclude on a queryset with an annotate field give attribute error.
Reported by: | AsgeirM | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.2 |
Severity: | Keywords: | annotate exclude AttributeError | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When using annotate on the queryset of a model that has a foreignkey relation, you may not use exclude towards relations afterwards. (See appended code for example)
If you were to use annotate on the model that is pointed at with the foreignkey, exclude with relations still work.
Excludeing before using annotate always works.
Tested with django.VERSION (1, 1, 0, 'final', 0) on python 2.4.3,
was also tested on the 2010.01.22 with the latest SVN.
SQL for creating example table
BEGIN; CREATE TABLE "rootnode" ( "id" serial NOT NULL PRIMARY KEY, "somefield" integer CHECK ("somefield" >= 0) NOT NULL); CREATE TABLE "childnode" ( "id" serial NOT NULL PRIMARY KEY, "parent_id" integer NOT NULL REFERENCES "rootnode" ("id") DEFERRABLE INITIALLY DEFERRED, "oddfield" integer CHECK ("oddfield" >= 0) NOT NULL, "evenfield" integer CHECK ("evenfield" >= 0) NOT NULL); COMMIT;
Code that demonstrates the AttributeError
from django.db import models from django.db.models import Min class RootNode(models.Model): somefield = models.PositiveIntegerField() class Meta: db_table = u'rootnode' class ChildNode(models.Model): parent = models.ForeignKey('RootNode', null = False) oddfield = models.PositiveIntegerField() evenfield = models.PositiveIntegerField() class Meta: db_table = u'childnode' rn1 = RootNode() rn1.somefield = 2 rn1.save() rn2 = RootNode() rn2.somefield = 3 rn2.save() cn1 = ChildNode() cn1.parent = rn1 cn1.oddfield = 43 cn1.evenfield = 42 cn1.save() # This node has even / odd swaped for 'testing' cn2 = ChildNode() cn2.parent = rn1 cn2.oddfield = 42 cn2.evenfield = 43 cn2.save() # Excluding before the annotates always works. q_set = ChildNode.objects.all().annotate(min_somefield=Min('parent__somefield')) # Works print q_set.exclude(oddfield=43).query print q_set.exclude(min_somefield=3) # Gives wrong result (empty set) print q_set.exclude(parent__somefield=1) # Attribute error print q_set.exclude(parent__somefield=1).query # Attribute error print q_set.exclude(parent__somefield=2).count()
Tracelog
AttributeError Traceback (most recent call last) /usr/lib/python2.4/site-packages/django/db/models/sql/query.pyc in __str__(self) 111 done by the database interface at execution time. 112 """ --> 113 sql, params = self.as_sql() 114 return sql % params 115 /usr/lib/python2.4/site-packages/django/db/models/sql/query.pyc in as_sql(self, with_limits, with_col_aliases) 402 403 qn = self.quote_name_unless_alias --> 404 where, w_params = self.where.as_sql(qn=qn) 405 having, h_params = self.having.as_sql(qn=qn) 406 params = [] /usr/lib/python2.4/site-packages/django/db/models/sql/where.pyc in as_sql(self, qn) 98 try: 99 if hasattr(child, 'as_sql'): --> 100 sql, params = child.as_sql(qn=qn) 101 else: 102 # A leaf node in the tree. /usr/lib/python2.4/site-packages/django/db/models/sql/where.pyc in as_sql(self, qn) 98 try: 99 if hasattr(child, 'as_sql'): --> 100 sql, params = child.as_sql(qn=qn) 101 else: 102 # A leaf node in the tree. /usr/lib/python2.4/site-packages/django/db/models/sql/where.pyc in as_sql(self, qn) 98 try: 99 if hasattr(child, 'as_sql'): --> 100 sql, params = child.as_sql(qn=qn) 101 else: 102 # A leaf node in the tree. /usr/lib/python2.4/site-packages/django/db/models/sql/where.pyc in as_sql(self, qn) 101 else: 102 # A leaf node in the tree. --> 103 sql, params = self.make_atom(child, qn) 104 105 except EmptyResultSet: /usr/lib/python2.4/site-packages/django/db/models/sql/where.pyc in make_atom(self, child, qn) 148 if isinstance(lvalue, tuple): 149 # A direct database column lookup. --> 150 field_sql = self.sql_for_columns(lvalue, qn) 151 else: 152 # A smart object with an as_sql() method. /usr/lib/python2.4/site-packages/django/db/models/sql/where.pyc in sql_for_columns(self, data, qn) 200 table_alias, name, db_type = data 201 if table_alias: --> 202 lhs = '%s.%s' % (qn(table_alias), qn(name)) 203 else: 204 lhs = qn(name) /usr/lib/python2.4/site-packages/django/db/models/sql/query.pyc in quote_name_unless_alias(self, name) 173 self.quote_cache[name] = name 174 return name --> 175 r = self.connection.ops.quote_name(name) 176 self.quote_cache[name] = r 177 return r /usr/lib/python2.4/site-packages/django/db/backends/postgresql/operations.pyc in quote_name(self, name) 61 62 def quote_name(self, name): ---> 63 if name.startswith('"') and name.endswith('"'): 64 return name # Quoting once is enough. 65 return '"%s"' % name AttributeError: 'NoneType' object has no attribute 'startswith'
Change History (8)
comment:1 by , 15 years ago
milestone: | → 1.2 |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 15 years ago
milestone: | 1.2 → 1.3 |
---|
comment:3 by , 14 years ago
Version: | 1.1 → 1.2 |
---|
Also attribute error in Django 1.2:
print q_set.filter(~Q(parent__somefield=1)).query
comment:4 by , 14 years ago
Ticket #13356 was closed as duplicate of this patch - It is true that is seems to be quite similar and there is more information here. But I think that it has more simple example of the problem and it could be also here.
Following code works :
from django.contrib.auth.models import User from django.db.models import Count User.objects.filter(id__in=[]).annotate(Count('groups')) [] User.objects.filter(id__in=[]).count() 0
But following code raise EmptyResultSet:
User.objects.filter(id__in=[]).annotate(Count('groups')).count()
comment:5 by , 14 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:6 by , 14 years ago
comment:8 by , 12 years ago
Component: | ORM aggregation → Database layer (models, ORM) |
---|
Not critical for 1.2.