Commit 06de130d authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

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.
parent 481f3f13
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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
+16 −0
Original line number Diff line number Diff line
@@ -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()
+24 −1
Original line number Diff line number Diff line
@@ -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)