| 467 | self.assertSequenceEqual(self.a1.report_set.all(), [self.r1]) |
| 468 | |
| 469 | def test_tickets_5324_6704(self): |
| 470 | self.assertSequenceEqual( |
| 471 | Item.objects.filter(tags__name="t4"), |
| 472 | [self.i4], |
| 473 | ) |
| 474 | self.assertSequenceEqual( |
| 475 | Item.objects.exclude(tags__name="t4").order_by("name").distinct(), |
| 476 | [self.i1, self.i3, self.i2], |
| 477 | ) |
| 478 | self.assertSequenceEqual( |
| 479 | Item.objects.exclude(tags__name="t4").order_by("name").distinct().reverse(), |
| 480 | [self.i2, self.i3, self.i1], |
| 481 | ) |
| 482 | self.assertSequenceEqual( |
| 483 | Author.objects.exclude(item__name="one").distinct().order_by("name"), |
| 484 | [self.a2, self.a3, self.a4], |
| 485 | ) |
| 486 | |
| 487 | # Excluding across a m2m relation when there is more than one related |
| 488 | # object associated was problematic. |
| 489 | self.assertSequenceEqual( |
| 490 | Item.objects.exclude(tags__name="t1").order_by("name"), |
| 491 | [self.i4, self.i3], |
| 492 | ) |
| 493 | self.assertSequenceEqual( |
| 494 | Item.objects.exclude(tags__name="t1").exclude(tags__name="t4"), |
| 495 | [self.i3], |
| 496 | ) |
| 497 | |
| 498 | # Excluding from a relation that cannot be NULL should not use outer |
| 499 | # joins. |
| 500 | query = Item.objects.exclude(creator__in=[self.a1, self.a2]).query |
| 501 | self.assertNotIn(LOUTER, [x.join_type for x in query.alias_map.values()]) |
| 502 | |
| 503 | # Similarly, when one of the joins cannot possibly, ever, involve NULL |
| 504 | # values (Author -> ExtraInfo, in the following), it should never be |
| 505 | # promoted to a left outer join. So the following query should only |
| 506 | # involve one "left outer" join (Author -> Item is 0-to-many). |
| 507 | qs = Author.objects.filter(id=self.a1.id).filter( |
| 508 | Q(extra__note=self.n1) | Q(item__note=self.n3) |
| 509 | ) |
| 510 | self.assertEqual( |
| 511 | len( |
| 512 | [ |
| 513 | x |
| 514 | for x in qs.query.alias_map.values() |
| 515 | if x.join_type == LOUTER and qs.query.alias_refcount[x.table_alias] |
| 516 | ] |
| 517 | ), |
| 518 | 1, |
| 519 | ) |
| 520 | |
| 521 | # The previous changes shouldn't affect nullable foreign key joins. |
| 522 | self.assertSequenceEqual( |
| 523 | Tag.objects.filter(parent__isnull=True).order_by("name"), [self.t1] |
| 524 | ) |
| 525 | self.assertSequenceEqual( |
| 526 | Tag.objects.exclude(parent__isnull=True).order_by("name"), |