Opened 13 years ago
Closed 12 years ago
#20250 closed Bug (fixed)
AttributeError when filtering annotated queryset with negated Q (via fk)
| Reported by: | Owned by: | ||
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.4 |
| Severity: | Normal | Keywords: | annotate AttributeError |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | yes | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
If these conditions are met:
- annotated queryset
- Q is filtering attribute related via foreign key
- Q is negation
Then AttributeError: 'NoneType' object has no attribute 'startswith' exception is throwed. Stack looks the same as in 12687 (fixed), see below.
Note that *all* conditions above are necessary, code works if one omitted. Reproducible with Django 1.4.5, python 2.6.8.
Traceback (most recent call last):
File "bug.py", line 16, in <module>
print qst.query
File "/usr/lib/python2.6/site-packages/django/db/models/sql/query.py", line 167, in __str__
sql, params = self.sql_with_params()
File "/usr/lib/python2.6/site-packages/django/db/models/sql/query.py", line 175, in sql_with_params
return self.get_compiler(DEFAULT_DB_ALIAS).as_sql()
File "/usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 82, in as_sql
where, w_params = self.query.where.as_sql(qn=qn, connection=self.connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 91, in as_sql
sql, params = child.as_sql(qn=qn, connection=connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 91, in as_sql
sql, params = child.as_sql(qn=qn, connection=connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 91, in as_sql
sql, params = child.as_sql(qn=qn, connection=connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 91, in as_sql
sql, params = child.as_sql(qn=qn, connection=connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 91, in as_sql
sql, params = child.as_sql(qn=qn, connection=connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 94, in as_sql
sql, params = self.make_atom(child, qn, connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 154, in make_atom
field_sql = self.sql_for_columns(lvalue, qn, connection)
File "/usr/lib/python2.6/site-packages/django/db/models/sql/where.py", line 227, in sql_for_columns
lhs = '%s.%s' % (qn(table_alias), qn(name))
File "/usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 49, in quote_name_unless_alias
r = self.connection.ops.quote_name(name)
File "/usr/lib/python2.6/site-packages/django/db/backends/sqlite3/base.py", line 145, in quote_name
if name.startswith('"') and name.endswith('"'):
AttributeError: 'NoneType' object has no attribute 'startswith'
Code snippet to reproduce the issue, bug.py:
from bug.models import *
from django.db.models import Q,Count
qobj=~Q(rtom3__x=0) #TOXIC
#qobj=~Q(x=0) #OK
#qobj=Q(rtom3__x=0) #OK
qst = M1.objects.annotate(Count('m2')) #TOXIC
#qst = M1.objects.all() #OK
qst = qst.filter(qobj)
#Gracefully returns [], no attempt to hit the database!!!!
#print qst
#Throws an exception!
print qst.query
and models.py:
from django.db import models
class M1(models.Model):
rtom3 = models.ForeignKey("M3")
x = models.IntegerField()
class M2(models.Model):
rtom1 = models.ForeignKey("M1")
class M3(models.Model):
x = models.IntegerField()
Change History (5)
comment:1 by , 13 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
comment:2 by , 13 years ago
| Needs tests: | set |
|---|---|
| Resolution: | fixed |
| Status: | closed → new |
| Triage Stage: | Unreviewed → Accepted |
Reverting my fixed resolution, regression test should be added even if this already works in master.
comment:3 by , 12 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:4 by , 12 years ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
Pull request with a regression test: https://github.com/django/django/pull/1165
comment:5 by , 12 years ago
| Owner: | set to |
|---|---|
| Resolution: | → fixed |
| Status: | new → closed |
This seems to work on master. The results of the print qst.query are:
SELECT "tester_m1"."id", "tester_m1"."rtom3_id", "tester_m1"."x", COUNT("tester_m2"."id") AS "m2__count" FROM "tester_m1" INNER JOIN "tester_m3" ON ( "tester_m1"."rtom3_id" = "tester_m3"."id" ) LEFT OUTER JOIN "tester_m2" ON ( "tester_m1"."id" = "tester_m2"."rtom1_id" ) WHERE NOT ("tester_m3"."x" = 0 ) GROUP BY "tester_m1"."id", "tester_m1"."rtom3_id", "tester_m1"."x"I haven't verified that the generated query is correct, but at least no errors are thrown.
Backpatching this to 1.4 will not happen as this isn't a critical bug (not a dataloss/security/regression/crash bug). I am marking this as fixed.