Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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.
  • Loading branch information...
commit 06de130dae8b7a6c95143077d7a82fab37da0bc0 1 parent 481f3f1
@akaariai akaariai authored
View
5 django/db/models/sql/query.py
@@ -1204,7 +1204,8 @@ def add_filter(self, filter_expr, connector=AND, negate=False,
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 @@ def split_exclude(self, filter_expr, prefix, can_reuse, names_with_path):
# 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
16 tests/queries/models.py
@@ -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
25 tests/queries/tests.py
@@ -24,7 +24,8 @@
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 @@ def test_exclude_many_to_many(self):
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)
Please sign in to comment.
Something went wrong with that request. Please try again.