| 1 | from django.contrib.auth.models import User |
| 2 | from django.test import TestCase |
| 3 | |
| 4 | from modeltests.model_inheritance.models import (BasePost, PostSubclass, |
| 5 | AuthorProfile, STATUS_GOOD, STATUS_BAD) |
| 6 | |
| 7 | class SubclassExclusionTestCase(TestCase): |
| 8 | def setUp(self): |
| 9 | # create some users! |
| 10 | self.user_good = User.objects.create_user('good', 'good', 'good') |
| 11 | self.user_neither = User.objects.create_user('neither', 'neither', 'neither') |
| 12 | self.user_bad = User.objects.create_user('bad', 'bad', 'bad') |
| 13 | |
| 14 | # create profiles for good & bad users (but don't make one for neither |
| 15 | self.profile_good = AuthorProfile.objects.create(user=self.user_good, status=STATUS_GOOD) |
| 16 | self.profile_bad = AuthorProfile.objects.create(user=self.user_bad, status=STATUS_BAD) |
| 17 | |
| 18 | # create some posts for the users |
| 19 | # note that i'm creating them in a different order - this is because the |
| 20 | # inner query generates an incorrect join but can produce results that |
| 21 | # "look" correct because of the primary keys being used. this ensures |
| 22 | # that the test will fail |
| 23 | self.post_bad1 = PostSubclass.objects.create(author=self.user_bad, title='Bad post1') |
| 24 | self.post_bad2 = PostSubclass.objects.create(author=self.user_bad, title='Bad post2') |
| 25 | self.post_good1 = PostSubclass.objects.create(author=self.user_good, title='Good post1') |
| 26 | self.post_good2 = PostSubclass.objects.create(author=self.user_good, title='Good post2') |
| 27 | self.post_neither1 = PostSubclass.objects.create(author=self.user_neither, title='Neither post1') |
| 28 | self.post_neither2 = PostSubclass.objects.create(author=self.user_neither, title='Neither post2') |
| 29 | |
| 30 | def test_filter_exclude(self): |
| 31 | ''' |
| 32 | This is the query being generated by the .exclude() -- NOTE that lines |
| 33 | 44-47 are basically saying "Give me posts where the author id is NOT |
| 34 | the base posts' id -- there's an extraneous join here that's messing |
| 35 | the query up. |
| 36 | |
| 37 | SELECT "model_inheritance_basepost"."id", "model_inheritance_basepost"."author_id", "model_inheritance_basepost"."title", "model_inheritance_postsubclass"."basepost_ptr_id" |
| 38 | FROM "model_inheritance_postsubclass" |
| 39 | |
| 40 | INNER JOIN "model_inheritance_basepost" |
| 41 | ON ("model_inheritance_postsubclass"."basepost_ptr_id" = "model_inheritance_basepost"."id") |
| 42 | |
| 43 | WHERE NOT (( |
| 44 | "model_inheritance_basepost"."author_id" IN ( |
| 45 | |
| 46 | SELECT U1."id" FROM "model_inheritance_basepost" U1 |
| 47 | INNER JOIN "auth_user" U2 |
| 48 | ON (U1."author_id" = U2."id") |
| 49 | INNER JOIN "model_inheritance_authorprofile" U3 |
| 50 | ON (U2."id" = U3."user_id") |
| 51 | WHERE U3."status" = 2 |
| 52 | ) AND |
| 53 | "model_inheritance_basepost"."author_id" IS NOT NULL |
| 54 | )) |
| 55 | |
| 56 | ORDER BY "model_inheritance_postsubclass"."basepost_ptr_id" ASC |
| 57 | ''' |
| 58 | # ensure that querying across joins works fine |
| 59 | good_post_qs = PostSubclass.objects.filter( |
| 60 | author__authorprofile__status=STATUS_GOOD |
| 61 | ) |
| 62 | self.assertEqual(list(good_post_qs), [self.post_good1, self.post_good2]) |
| 63 | |
| 64 | # this works all fine and well, but say we want to get all posts where |
| 65 | # the authors' status is anything *but* bad |
| 66 | not_bad_post_qs = PostSubclass.objects.exclude( |
| 67 | author__authorprofile__status=STATUS_BAD |
| 68 | ) |
| 69 | self.assertEqual(list(not_bad_post_qs), [self.post_good1, self.post_good2, self.post_neither1, self.post_neither2]) |