Opened 12 years ago

Closed 12 years ago

Last modified 11 years ago

#18248 closed Bug (fixed)

Determining SQL statement for a proxy model breaks count

Reported by: zmsmith Owned by: Anssi Kääriäinen
Component: Database layer (models, ORM) Version: 1.4
Severity: Normal Keywords: count, proxy
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given a proxy model Foo:

query = Foo.objects.all()
query.count()

5

query_str = str(query)
query.count()

DatabaseError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near

Change History (10)

comment:1 by zmsmith, 12 years ago

query = Foo.objects.all()
query.count()
# returns correctly
query_str = str(query)
query.count()
# raises DataBaseError

comment:2 by zmsmith, 12 years ago

Having a lot of trouble with the formatting. Hopefully it's still clear.

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

Owner: changed from nobody to Anssi Kääriäinen
Triage Stage: UnreviewedAccepted

Hint: use {{{code here}}} for formatting code blocks.

I can verify this, happens on SQLite too. This does not happen when not using proxy-models. Test setup:

class DumbCategory(models.Model):
    pass

class ProxyCategory(DumbCategory):
    class Meta:
        proxy = True

def test_evaluated_proxy_count(self):
    ProxyCategory.objects.create()
    qs = ProxyCategory.objects.all()
    self.assertEqual(qs.count(), 1)
    str(qs.query)
    self.assertEqual(qs.count(), 1)

The problem seems to be related to str(qs.query) generating the query string without actually executing it. If you execute the query instead of generating the query string the second qs.count() will just see the cached results and thus not execute a query at all. No error in that case.

comment:4 by Anssi Kääriäinen, 12 years ago

I think I nailed this one - the reason was that proxy model's parent tables were added multiple times to included_inherited_models in sql/query.py. The included_inherited_models seems to be meant only for multitable inheritance. The mistake caused the proxy model table to be removed multiple times from the query in remove_inherited_models().

See pull request https://github.com/django/django/pull/32 for patch.

comment:5 by Anssi Kääriäinen, 12 years ago

Resolution: fixed
Status: newclosed

comment:6 by Anssi Kääriäinen, 12 years ago

Fix proxy model Query.remove_inherited_models()

Fixed #18248 -- proxy models were added to included_inherited_models
in sql.query.Query. The variable is meant to be used for multitable
inheritance only. This mistake caused problems in situations where
proxy model's query was reused.

Changeset: c2e1ecb4b136016ab2996712aa0583fd91657bc9

comment:7 by Anssi Kääriäinen, 12 years ago

Fix proxy model Query.remove_inherited_models()

Fixed #18248 -- proxy models were added to included_inherited_models
in sql.query.Query. The variable is meant to be used for multitable
inheritance only. This mistake caused problems in situations where
proxy model's query was reused.

Changeset: c2e1ecb4b136016ab2996712aa0583fd91657bc9

comment:8 by Anssi Kääriäinen, 12 years ago

Fix proxy model Query.remove_inherited_models()

Fixed #18248 -- proxy models were added to included_inherited_models
in sql.query.Query. The variable is meant to be used for multitable
inheritance only. This mistake caused problems in situations where
proxy model's query was reused.

Changeset: c2e1ecb4b136016ab2996712aa0583fd91657bc9

comment:9 by Aymeric Augustin, 12 years ago

Sorry for the spam -- GitHub integration in progress.

in reply to:  9 comment:10 by cdawson@…, 11 years ago

Replying to aaugustin:

I hit this error on my upgrade to Django 1.4 getting the error:

DatabaseError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near at line 1")

My code was: self._cached_total = self._queryset.count()
And unfortunately: self._queryset.all().count() didn't help. Same error.

I worked around it by changing my code to:

self._cached_total = self._queryset.values("id").count()

Just figured I'd post it here in case it saved someone else some headaches.

-Cam

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