Skip to content

Commit 4f302e0

Browse files
authored
Fix count for queries using Subquery or Exists (#15)
1 parent 63113c1 commit 4f302e0

File tree

9 files changed

+97
-1
lines changed

9 files changed

+97
-1
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ install:
5555

5656
script:
5757
- pip install -r django/tests/requirements/py3.txt
58+
- python manage.py test
5859
- ./test.sh

manage.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env python
2+
import os
3+
import sys
4+
5+
if __name__ == "__main__":
6+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings")
7+
8+
from django.core.management import execute_from_command_line
9+
10+
execute_from_command_line(sys.argv)

sql_server/pyodbc/compiler.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from itertools import chain
33

44
from django.db.models.aggregates import Avg, Count, StdDev, Variance
5-
from django.db.models.expressions import Exists, OrderBy, Ref, Value
5+
from django.db.models.expressions import Exists, OrderBy, Ref, Subquery, Value
66
from django.db.models.functions import (
77
Chr, ConcatPair, Greatest, Least, Length, LPad, Repeat, RPad, StrIndex, Substr, Trim
88
)
@@ -374,6 +374,10 @@ def compile(self, node, select_format=False):
374374
node = self._as_microsoft(node)
375375
return super().compile(node, select_format)
376376

377+
def collapse_group_by(self, expressions, having):
378+
expressions = super().collapse_group_by(expressions, having)
379+
return [e for e in expressions if not isinstance(e, Subquery)]
380+
377381
def _as_microsoft(self, node):
378382
as_microsoft = None
379383
if isinstance(node, Avg):

testapp/migrations/0001_initial.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 2.2.8.dev20191112211527 on 2019-11-15 01:38
2+
3+
from django.db import migrations, models
4+
import django
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
initial = True
10+
11+
dependencies = [
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name='Post',
17+
fields=[
18+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19+
('title', models.CharField(max_length=255, verbose_name='title')),
20+
],
21+
),
22+
migrations.CreateModel(
23+
name='Comment',
24+
fields=[
25+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
26+
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='testapp.Post')),
27+
('text', models.TextField(verbose_name='text')),
28+
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
29+
],
30+
),
31+
]

testapp/migrations/__init__.py

Whitespace-only changes.

testapp/models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from django.db import models
2+
from django.utils import timezone
3+
4+
5+
class Post(models.Model):
6+
title = models.CharField('title', max_length=255)
7+
8+
def __str__(self):
9+
return self.title
10+
11+
12+
class Comment(models.Model):
13+
post = models.ForeignKey(Post, on_delete=models.CASCADE)
14+
text = models.TextField('text')
15+
created_at = models.DateTimeField(default=timezone.now)
16+
17+
def __str__(self):
18+
return self.text

testapp/settings.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
'other': dj_database_url.config(env='DATABASE_URL_OTHER', default='sqlite:///db.sqlite'),
66
}
77

8+
INSTALLED_APPS = (
9+
'django.contrib.contenttypes',
10+
'django.contrib.staticfiles',
11+
'django.contrib.auth',
12+
'testapp',
13+
)
14+
815
SECRET_KEY = "django_tests_secret_key"
916

1017
# Use a fast hasher to speed up tests.

testapp/tests/__init__.py

Whitespace-only changes.

testapp/tests/test_expressions.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from django.db.models.expressions import Exists, OuterRef, Subquery
2+
from django.test import TestCase
3+
4+
from ..models import Comment, Post
5+
6+
7+
class TestSubquery(TestCase):
8+
def setUp(self):
9+
self.post = Post.objects.create(title="foo")
10+
11+
def test_with_count(self):
12+
newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
13+
Post.objects.annotate(
14+
post_exists=Subquery(newest.values('text')[:1])
15+
).filter(post_exists=True).count()
16+
17+
18+
class TestExists(TestCase):
19+
def setUp(self):
20+
self.post = Post.objects.create(title="foo")
21+
22+
def test_with_count(self):
23+
Post.objects.annotate(
24+
post_exists=Exists(Post.objects.all())
25+
).filter(post_exists=True).count()

0 commit comments

Comments
 (0)