Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12429 -- Ensure that raw queries call resolve_columns if the b…

…ackend defines it. This ensures (as much as possible) that the model values returned by a raw query match that in normal queries. Thanks to Ian Kelly for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12904 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f7cf58ac0ebf720e5c48f00e99c31cf39c4fca50 1 parent c39ec6d
Russell Keith-Magee authored April 01, 2010
11  django/db/models/query.py
@@ -1407,20 +1407,27 @@ def model_fields(self):
1407 1407
             self._model_fields = {}
1408 1408
             for field in self.model._meta.fields:
1409 1409
                 name, column = field.get_attname_column()
1410  
-                self._model_fields[converter(column)] = name
  1410
+                self._model_fields[converter(column)] = field
1411 1411
         return self._model_fields
1412 1412
 
1413 1413
     def transform_results(self, values):
1414 1414
         model_init_kwargs = {}
1415 1415
         annotations = ()
1416 1416
 
  1417
+        # Perform database backend type resolution
  1418
+        connection = connections[self.db]
  1419
+        compiler = connection.ops.compiler('SQLCompiler')(self.query, connection, self.db)
  1420
+        if hasattr(compiler, 'resolve_columns'):
  1421
+            fields = [self.model_fields.get(c,None) for c in self.columns]
  1422
+            values = compiler.resolve_columns(values, fields)
  1423
+
1417 1424
         # Associate fields to values
1418 1425
         for pos, value in enumerate(values):
1419 1426
             column = self.columns[pos]
1420 1427
 
1421 1428
             # Separate properties from annotations
1422 1429
             if column in self.model_fields.keys():
1423  
-                model_init_kwargs[self.model_fields[column]] = value
  1430
+                model_init_kwargs[self.model_fields[column].attname] = value
1424 1431
             else:
1425 1432
                 annotations += (column, value),
1426 1433
 
4  django/db/models/sql/compiler.py
@@ -14,10 +14,6 @@ def __init__(self, query, connection, using):
14 14
         self.using = using
15 15
         self.quote_cache = {}
16 16
 
17  
-        # Check that the compiler will be able to execute the query
18  
-        for alias, aggregate in self.query.aggregate_select.items():
19  
-            self.connection.ops.check_aggregate_support(aggregate)
20  
-
21 17
     def pre_sql_setup(self):
22 18
         """
23 19
         Does any necessary class setup immediately prior to producing SQL. This
5  django/db/models/sql/query.py
@@ -189,6 +189,11 @@ def get_compiler(self, using=None, connection=None):
189 189
             raise ValueError("Need either using or connection")
190 190
         if using:
191 191
             connection = connections[using]
  192
+
  193
+        # Check that the compiler will be able to execute the query
  194
+        for alias, aggregate in self.aggregate_select.items():
  195
+            connection.ops.check_aggregate_support(aggregate)
  196
+
192 197
         return connection.ops.compiler(self.compiler)(self, connection, using)
193 198
 
194 199
     def get_meta(self):
16  ...s/modeltests/raw_query/fixtures/initial_data.json → ...odeltests/raw_query/fixtures/raw_query_books.json
@@ -40,7 +40,9 @@
40 40
         "model": "raw_query.book",
41 41
         "fields": {
42 42
             "author": 1,
43  
-            "title": "The awesome book"
  43
+            "title": "The awesome book",
  44
+            "paperback": false,
  45
+            "opening_line": "It was a bright cold day in April and the clocks were striking thirteen."
44 46
         }
45 47
     },
46 48
     {
@@ -48,7 +50,9 @@
48 50
         "model": "raw_query.book",
49 51
         "fields": {
50 52
             "author": 1,
51  
-            "title": "The horrible book"
  53
+            "title": "The horrible book",
  54
+            "paperback": true,
  55
+            "opening_line": "On an evening in the latter part of May a middle-aged man was walking homeward from Shaston to the village of Marlott, in the adjoining Vale of Blakemore, or Blackmoor."
52 56
         }
53 57
     },
54 58
     {
@@ -56,7 +60,9 @@
56 60
         "model": "raw_query.book",
57 61
         "fields": {
58 62
             "author": 1,
59  
-            "title": "Another awesome book"
  63
+            "title": "Another awesome book",
  64
+            "paperback": false,
  65
+            "opening_line": "A squat grey building of only thirty-four stories."
60 66
         }
61 67
     },
62 68
     {
@@ -64,7 +70,9 @@
64 70
         "model": "raw_query.book",
65 71
         "fields": {
66 72
             "author": 3,
67  
-            "title": "Some other book"
  73
+            "title": "Some other book",
  74
+            "paperback": true,
  75
+            "opening_line": "It was the day my grandmother exploded."
68 76
         }
69 77
     },
70 78
     {
2  tests/modeltests/raw_query/models.py
@@ -17,6 +17,8 @@ def __init__(self, *args, **kwargs):
17 17
 class Book(models.Model):
18 18
     title = models.CharField(max_length=255)
19 19
     author = models.ForeignKey(Author)
  20
+    paperback = models.BooleanField()
  21
+    opening_line = models.TextField()
20 22
 
21 23
 class Coffee(models.Model):
22 24
     brand = models.CharField(max_length=255, db_column="name")
15  tests/modeltests/raw_query/tests.py
@@ -7,6 +7,7 @@
7 7
 
8 8
 
9 9
 class RawQueryTests(TestCase):
  10
+    fixtures = ['raw_query_books.json']
10 11
 
11 12
     def assertSuccessfulRawQuery(self, model, query, expected_results,
12 13
             expected_annotations=(), params=[], translations=None):
@@ -14,10 +15,10 @@ def assertSuccessfulRawQuery(self, model, query, expected_results,
14 15
         Execute the passed query against the passed model and check the output
15 16
         """
16 17
         results = list(model.objects.raw(query, params=params, translations=translations))
17  
-        self.assertProcessed(results, expected_results, expected_annotations)
  18
+        self.assertProcessed(model, results, expected_results, expected_annotations)
18 19
         self.assertAnnotations(results, expected_annotations)
19 20
 
20  
-    def assertProcessed(self, results, orig, expected_annotations=()):
  21
+    def assertProcessed(self, model, results, orig, expected_annotations=()):
21 22
         """
22 23
         Compare the results of a raw query against expected results
23 24
         """
@@ -27,7 +28,13 @@ def assertProcessed(self, results, orig, expected_annotations=()):
27 28
             for annotation in expected_annotations:
28 29
                 setattr(orig_item, *annotation)
29 30
 
30  
-            self.assertEqual(item.id, orig_item.id)
  31
+            for field in model._meta.fields:
  32
+                # Check that all values on the model are equal
  33
+                self.assertEquals(getattr(item,field.attname),
  34
+                                  getattr(orig_item,field.attname))
  35
+                # This includes checking that they are the same type
  36
+                self.assertEquals(type(getattr(item,field.attname)),
  37
+                                  type(getattr(orig_item,field.attname)))
31 38
 
32 39
     def assertNoAnnotations(self, results):
33 40
         """
@@ -115,7 +122,7 @@ def testParams(self):
115 122
         author = Author.objects.all()[2]
116 123
         params = [author.first_name]
117 124
         results = list(Author.objects.raw(query, params=params))
118  
-        self.assertProcessed(results, [author])
  125
+        self.assertProcessed(Author, results, [author])
119 126
         self.assertNoAnnotations(results)
120 127
         self.assertEqual(len(results), 1)
121 128
 

0 notes on commit f7cf58a

Please sign in to comment.
Something went wrong with that request. Please try again.