| | 1 | from django.test import TestCase |
| | 2 | from datetime import datetime |
| | 3 | from models import Author, Book, Coffee, Reviewer |
| | 4 | |
| | 5 | from django.db.models.query import InsuficientFieldsException |
| | 6 | from django.db.models.sql.query import InvalidQueryException |
| | 7 | |
| | 8 | class RawQueryTests(TestCase): |
| | 9 | |
| | 10 | def setUp(self): |
| | 11 | self.authors = [] |
| | 12 | self.books = [] |
| | 13 | self.coffees = [] |
| | 14 | self.reviewers = [] |
| | 15 | |
| | 16 | self.authors.append(Author.objects.create( |
| | 17 | first_name="Joe", |
| | 18 | last_name="Smith", |
| | 19 | dob=datetime(year=1950, month=9, day=20), |
| | 20 | )) |
| | 21 | self.authors.append(Author.objects.create( |
| | 22 | first_name="Jill", |
| | 23 | last_name="Doe", |
| | 24 | dob=datetime(year=1920, month=4, day=2), |
| | 25 | )) |
| | 26 | self.authors.append(Author.objects.create( |
| | 27 | first_name="Bob", |
| | 28 | last_name="Smith", |
| | 29 | dob=datetime(year=1986, month=1, day=25), |
| | 30 | )) |
| | 31 | self.authors.append(Author.objects.create( |
| | 32 | first_name="Bill", |
| | 33 | last_name="Jones", |
| | 34 | dob=datetime(year=1932, month=5, day=10), |
| | 35 | )) |
| | 36 | |
| | 37 | self.books.append(Book.objects.create( |
| | 38 | title = 'The awesome book', |
| | 39 | author = self.authors[0], |
| | 40 | )) |
| | 41 | |
| | 42 | self.books.append(Book.objects.create( |
| | 43 | title = 'The horrible book', |
| | 44 | author = self.authors[0], |
| | 45 | )) |
| | 46 | |
| | 47 | self.books.append(Book.objects.create( |
| | 48 | title = 'Another awesome book', |
| | 49 | author = self.authors[0], |
| | 50 | )) |
| | 51 | |
| | 52 | self.books.append(Book.objects.create( |
| | 53 | title = 'Some other book', |
| | 54 | author = self.authors[2], |
| | 55 | )) |
| | 56 | |
| | 57 | self.coffees.append(Coffee.objects.create(brand="dunkin doughnuts")) |
| | 58 | self.coffees.append(Coffee.objects.create(brand="starbucks")) |
| | 59 | |
| | 60 | self.reviewers.append(Reviewer.objects.create()) |
| | 61 | self.reviewers.append(Reviewer.objects.create()) |
| | 62 | self.reviewers[0].reviewed.add(self.books[3]) |
| | 63 | self.reviewers[0].reviewed.add(self.books[1]) |
| | 64 | self.reviewers[0].reviewed.add(self.books[2]) |
| | 65 | |
| | 66 | def assertSuccessfulRawQuery(self, model, query, expected_results, \ |
| | 67 | expected_annotations=(), params=[], translations=None): |
| | 68 | """ |
| | 69 | Execute the passed query against the passed model and check the output |
| | 70 | """ |
| | 71 | results = model.objects.raw(query=query, params=params, \ |
| | 72 | translations=translations) |
| | 73 | self.assertProcessed(results, expected_results, expected_annotations) |
| | 74 | self.assertAnnotations(results, expected_annotations) |
| | 75 | |
| | 76 | def assertProcessed(self, results, orig, expected_annotations=()): |
| | 77 | """ |
| | 78 | Compare the results of a raw query against expected results |
| | 79 | """ |
| | 80 | self.assertEqual(len(results), len(orig)) |
| | 81 | for index, item in enumerate(results): |
| | 82 | orig_item = orig[index] |
| | 83 | for annotation in expected_annotations: |
| | 84 | setattr(orig_item, *annotation) |
| | 85 | |
| | 86 | self.assertEqual(item.id, orig_item.id) |
| | 87 | |
| | 88 | def assertNoAnnotations(self, results): |
| | 89 | """ |
| | 90 | Check that the results of a raw query contain no annotations |
| | 91 | """ |
| | 92 | self.assertAnnotations(results, ()) |
| | 93 | |
| | 94 | def assertAnnotations(self, results, expected_annotations): |
| | 95 | """ |
| | 96 | Check that the passed raw query results contain the expected |
| | 97 | annotations |
| | 98 | """ |
| | 99 | self.assertEqual(results._annotations, expected_annotations) |
| | 100 | |
| | 101 | def testSimpleRawQuery(self): |
| | 102 | """ |
| | 103 | Basic test of raw query with a simple database query |
| | 104 | """ |
| | 105 | query = "SELECT * FROM raw_query_author" |
| | 106 | self.assertSuccessfulRawQuery(Author, query, self.authors) |
| | 107 | |
| | 108 | def testFkeyRawQuery(self): |
| | 109 | """ |
| | 110 | Test of a simple raw query against a model containing a foreign key |
| | 111 | """ |
| | 112 | query = "SELECT * FROM raw_query_book" |
| | 113 | self.assertSuccessfulRawQuery(Book, query, self.books) |
| | 114 | |
| | 115 | def testDBColumnHandler(self): |
| | 116 | """ |
| | 117 | Test of a simple raw query against a model containing a field with |
| | 118 | db_column defined. |
| | 119 | """ |
| | 120 | query = "SELECT * FROM raw_query_coffee" |
| | 121 | self.assertSuccessfulRawQuery(Coffee, query, self.coffees) |
| | 122 | |
| | 123 | def testOrderHandler(self): |
| | 124 | """ |
| | 125 | Test of raw raw query's tolerance for columns being returned in any |
| | 126 | order |
| | 127 | """ |
| | 128 | selects = ( |
| | 129 | ('dob, last_name, first_name, id'), |
| | 130 | ('last_name, dob, first_name, id'), |
| | 131 | ('first_name, last_name, dob, id'), |
| | 132 | ) |
| | 133 | |
| | 134 | for select in selects: |
| | 135 | query = "SELECT %s FROM raw_query_author" % select |
| | 136 | self.assertSuccessfulRawQuery(Author, query, self.authors) |
| | 137 | |
| | 138 | def testTranslations(self): |
| | 139 | """ |
| | 140 | Test of raw query's optional ability to translate unexpected result |
| | 141 | column names to specific model fields |
| | 142 | """ |
| | 143 | query = "SELECT first_name AS first, last_name AS last, dob, id FROM raw_query_author" |
| | 144 | translations = ( |
| | 145 | ('first', 'first_name'), |
| | 146 | ('last', 'last_name'), |
| | 147 | ) |
| | 148 | self.assertSuccessfulRawQuery(Author, query, self.authors, translations=translations) |
| | 149 | |
| | 150 | def testParams(self): |
| | 151 | """ |
| | 152 | Test passing optional query parameters |
| | 153 | """ |
| | 154 | query = "SELECT * FROM raw_query_author WHERE first_name = %s" |
| | 155 | params = [self.authors[2].first_name] |
| | 156 | results = Author.objects.raw(query=query, params=params) |
| | 157 | self.assertProcessed(results, [self.authors[2]]) |
| | 158 | self.assertNoAnnotations(results) |
| | 159 | self.assertEqual(len(results), 1) |
| | 160 | |
| | 161 | def testManyToMany(self): |
| | 162 | """ |
| | 163 | Test of a simple raw query against a model containing a m2m field |
| | 164 | """ |
| | 165 | query = "SELECT * FROM raw_query_reviewer" |
| | 166 | self.assertSuccessfulRawQuery(Reviewer, query, self.reviewers) |
| | 167 | |
| | 168 | def testExtraConversions(self): |
| | 169 | """ |
| | 170 | Test to insure that extra tranlations are ignored. |
| | 171 | """ |
| | 172 | query = "SELECT * FROM raw_query_author" |
| | 173 | translations = (('something', 'else'),) |
| | 174 | self.assertSuccessfulRawQuery(Author, query, self.authors, translations=translations) |
| | 175 | |
| | 176 | def testInsufficientColumns(self): |
| | 177 | query = "SELECT first_name, dob FROM raw_query_author" |
| | 178 | raised = False |
| | 179 | try: |
| | 180 | results = Author.objects.raw(query) |
| | 181 | results_list = list(results) |
| | 182 | except InsuficientFieldsException: |
| | 183 | raised = True |
| | 184 | |
| | 185 | self.assertTrue(raised) |
| | 186 | |
| | 187 | def testAnnotations(self): |
| | 188 | query = "SELECT a.*, count(b.id) as book_count FROM raw_query_author a LEFT JOIN raw_query_book b ON a.id = b.author_id GROUP BY a.id, a.first_name, a.last_name, a.dob ORDER BY a.id" |
| | 189 | expected_annotations = ( |
| | 190 | ('book_count', 3), |
| | 191 | ('book_count', 0), |
| | 192 | ('book_count', 1), |
| | 193 | ('book_count', 0), |
| | 194 | ) |
| | 195 | self.assertSuccessfulRawQuery(Author, query, self.authors, expected_annotations) |
| | 196 | |
| | 197 | def testInvalidQuery(self): |
| | 198 | query = "UPDATE raw_query_author SET first_name='thing' WHERE first_name='Joe'" |
| | 199 | self.assertRaises(InvalidQueryException, Author.objects.raw, query) |
| | 200 | No newline at end of file |