Fixed #12823 -- Was already fixed in master, tests added

Also added a little improvement to sql/query.py to get rid of
non-necessary IS NOT NULL check.
This commit is contained in:
Anssi Kääriäinen 2013-02-28 15:04:12 +02:00
parent 481f3f13b5
commit 06de130dae
3 changed files with 43 additions and 3 deletions

View File

@ -1204,7 +1204,8 @@ class Query(object):
if negate:
self.promote_joins(join_list)
if lookup_type != 'isnull' and (self.is_nullable(target) or len(join_list) > 1):
if (lookup_type != 'isnull' and (
self.is_nullable(target) or self.alias_map[join_list[-1]].join_type == self.LOUTER)):
# The condition added here will be SQL like this:
# NOT (col IS NOT NULL), where the first NOT is added in
# upper layers of code. The reason for addition is that if col
@ -1447,7 +1448,7 @@ class Query(object):
# nothing
if self.is_nullable(query.select[0].field):
alias, col = query.select[0].col
query.where.add((Constraint(alias, col, None), 'isnull', False), AND)
query.where.add((Constraint(alias, col, query.select[0].field), 'isnull', False), AND)
# Still make sure that the trimmed parts in the inner query and
# trimmed prefix are in sync. So, use the trimmed_joins to make sure

View File

@ -454,3 +454,19 @@ class Program(models.Model):
class Channel(models.Model):
programs = models.ManyToManyField(Program)
identifier = models.OneToOneField(Identifier)
class Book(models.Model):
title = models.TextField()
chapter = models.ForeignKey('Chapter')
class Chapter(models.Model):
title = models.TextField()
paragraph = models.ForeignKey('Paragraph')
class Paragraph(models.Model):
text = models.TextField()
page = models.ManyToManyField('Page')
class Page(models.Model):
text = models.TextField()

View File

@ -24,7 +24,8 @@ from .models import (Annotation, Article, Author, Celebrity, Child, Cover,
Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory,
SpecialCategory, OneToOneCategory, NullableName, ProxyCategory,
SingleObject, RelatedObject, ModelA, ModelD, Responsibility, Job,
JobResponsibilities, BaseA, Identifier, Program, Channel)
JobResponsibilities, BaseA, Identifier, Program, Channel, Page, Paragraph,
Chapter, Book)
class BaseQuerysetTest(TestCase):
@ -2638,3 +2639,25 @@ class ManyToManyExcludeTest(TestCase):
Identifier.objects.exclude(program__channel=None).order_by('name'),
['<Identifier: program>']
)
def test_ticket_12823(self):
pg3 = Page.objects.create(text='pg3')
pg2 = Page.objects.create(text='pg2')
pg1 = Page.objects.create(text='pg1')
pa1 = Paragraph.objects.create(text='pa1')
pa1.page = [pg1, pg2]
pa2 = Paragraph.objects.create(text='pa2')
pa2.page = [pg2, pg3]
pa3 = Paragraph.objects.create(text='pa3')
ch1 = Chapter.objects.create(title='ch1', paragraph=pa1)
ch2 = Chapter.objects.create(title='ch2', paragraph=pa2)
ch3 = Chapter.objects.create(title='ch3', paragraph=pa3)
b1 = Book.objects.create(title='b1', chapter=ch1)
b2 = Book.objects.create(title='b2', chapter=ch2)
b3 = Book.objects.create(title='b3', chapter=ch3)
q = Book.objects.exclude(chapter__paragraph__page__text='pg1')
self.assertNotIn('IS NOT NULL', str(q.query))
self.assertEqual(len(q), 2)
self.assertNotIn(b1, q)
self.assertIn(b2, q)
self.assertIn(b3, q)