2013-07-30 01:19:04 +08:00
from __future__ import unicode_literals
2011-10-14 02:04:12 +08:00
2010-02-24 03:39:06 +08:00
from datetime import date
2012-09-07 22:58:17 +08:00
from django . db . models . query_utils import InvalidQuery
2013-06-28 11:15:03 +08:00
from django . test import TestCase , skipUnlessDBFeature
2010-02-24 03:39:06 +08:00
2015-07-23 02:54:42 +08:00
from . models import Author , Book , BookFkAsPk , Coffee , FriendlyAuthor , Reviewer
2010-02-24 03:39:06 +08:00
2009-12-20 10:46:58 +08:00
class RawQueryTests ( TestCase ) :
2015-02-23 08:53:57 +08:00
@classmethod
def setUpTestData ( cls ) :
cls . a1 = Author . objects . create ( first_name = ' Joe ' , last_name = ' Smith ' , dob = date ( 1950 , 9 , 20 ) )
cls . a2 = Author . objects . create ( first_name = ' Jill ' , last_name = ' Doe ' , dob = date ( 1920 , 4 , 2 ) )
cls . a3 = Author . objects . create ( first_name = ' Bob ' , last_name = ' Smith ' , dob = date ( 1986 , 1 , 25 ) )
cls . a4 = Author . objects . create ( first_name = ' Bill ' , last_name = ' Jones ' , dob = date ( 1932 , 5 , 10 ) )
cls . b1 = Book . objects . create ( title = ' The awesome book ' , author = cls . a1 , paperback = False , opening_line = ' It was a bright cold day in April and the clocks were striking thirteen. ' )
cls . b2 = Book . objects . create ( title = ' The horrible book ' , author = cls . a1 , paperback = True , 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. ' )
cls . b3 = Book . objects . create ( title = ' Another awesome book ' , author = cls . a1 , paperback = False , opening_line = ' A squat grey building of only thirty-four stories. ' )
cls . b4 = Book . objects . create ( title = ' Some other book ' , author = cls . a3 , paperback = True , opening_line = ' It was the day my grandmother exploded. ' )
cls . c1 = Coffee . objects . create ( brand = ' dunkin doughnuts ' )
cls . c2 = Coffee . objects . create ( brand = ' starbucks ' )
cls . r1 = Reviewer . objects . create ( )
cls . r2 = Reviewer . objects . create ( )
cls . r1 . reviewed . add ( cls . b2 , cls . b3 , cls . b4 )
2009-12-20 10:46:58 +08:00
def assertSuccessfulRawQuery ( self , model , query , expected_results ,
expected_annotations = ( ) , params = [ ] , translations = None ) :
"""
Execute the passed query against the passed model and check the output
"""
2009-12-22 23:18:51 +08:00
results = list ( model . objects . raw ( query , params = params , translations = translations ) )
2010-04-02 00:48:16 +08:00
self . assertProcessed ( model , results , expected_results , expected_annotations )
2009-12-20 10:46:58 +08:00
self . assertAnnotations ( results , expected_annotations )
2010-04-02 00:48:16 +08:00
def assertProcessed ( self , model , results , orig , expected_annotations = ( ) ) :
2009-12-20 10:46:58 +08:00
"""
Compare the results of a raw query against expected results
"""
self . assertEqual ( len ( results ) , len ( orig ) )
for index , item in enumerate ( results ) :
orig_item = orig [ index ]
for annotation in expected_annotations :
setattr ( orig_item , * annotation )
2010-04-02 00:48:16 +08:00
for field in model . _meta . fields :
# Check that all values on the model are equal
2013-12-13 04:23:24 +08:00
self . assertEqual (
getattr ( item , field . attname ) ,
getattr ( orig_item , field . attname )
)
2010-04-02 00:48:16 +08:00
# This includes checking that they are the same type
2013-12-13 04:23:24 +08:00
self . assertEqual (
type ( getattr ( item , field . attname ) ) ,
type ( getattr ( orig_item , field . attname ) )
)
2009-12-20 10:46:58 +08:00
def assertNoAnnotations ( self , results ) :
"""
Check that the results of a raw query contain no annotations
"""
self . assertAnnotations ( results , ( ) )
def assertAnnotations ( self , results , expected_annotations ) :
"""
Check that the passed raw query results contain the expected
annotations
"""
if expected_annotations :
for index , result in enumerate ( results ) :
annotation , value = expected_annotations [ index ]
self . assertTrue ( hasattr ( result , annotation ) )
self . assertEqual ( getattr ( result , annotation ) , value )
2014-07-08 07:08:42 +08:00
def test_simple_raw_query ( self ) :
2009-12-20 10:46:58 +08:00
"""
Basic test of raw query with a simple database query
"""
query = " SELECT * FROM raw_query_author "
authors = Author . objects . all ( )
self . assertSuccessfulRawQuery ( Author , query , authors )
2014-07-08 07:08:42 +08:00
def test_raw_query_lazy ( self ) :
2009-12-20 10:46:58 +08:00
"""
Raw queries are lazy : they aren ' t actually executed until they ' re
iterated over .
"""
q = Author . objects . raw ( ' SELECT * FROM raw_query_author ' )
2014-10-28 18:02:56 +08:00
self . assertIsNone ( q . query . cursor )
2009-12-20 10:46:58 +08:00
list ( q )
2014-10-28 18:02:56 +08:00
self . assertIsNotNone ( q . query . cursor )
2009-12-20 10:46:58 +08:00
2014-07-08 07:08:42 +08:00
def test_FK_raw_query ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test of a simple raw query against a model containing a foreign key
"""
query = " SELECT * FROM raw_query_book "
books = Book . objects . all ( )
self . assertSuccessfulRawQuery ( Book , query , books )
2014-07-08 07:08:42 +08:00
def test_db_column_handler ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test of a simple raw query against a model containing a field with
db_column defined .
"""
query = " SELECT * FROM raw_query_coffee "
coffees = Coffee . objects . all ( )
self . assertSuccessfulRawQuery ( Coffee , query , coffees )
2014-07-08 07:08:42 +08:00
def test_order_handler ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test of raw raw query ' s tolerance for columns being returned in any
order
"""
selects = (
( ' dob, last_name, first_name, id ' ) ,
( ' last_name, dob, first_name, id ' ) ,
( ' first_name, last_name, dob, id ' ) ,
)
for select in selects :
query = " SELECT %s FROM raw_query_author " % select
authors = Author . objects . all ( )
self . assertSuccessfulRawQuery ( Author , query , authors )
2014-07-08 07:08:42 +08:00
def test_translations ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test of raw query ' s optional ability to translate unexpected result
column names to specific model fields
"""
query = " SELECT first_name AS first, last_name AS last, dob, id FROM raw_query_author "
translations = { ' first ' : ' first_name ' , ' last ' : ' last_name ' }
authors = Author . objects . all ( )
self . assertSuccessfulRawQuery ( Author , query , authors , translations = translations )
2014-07-08 07:08:42 +08:00
def test_params ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test passing optional query parameters
"""
query = " SELECT * FROM raw_query_author WHERE first_name = %s "
author = Author . objects . all ( ) [ 2 ]
params = [ author . first_name ]
2013-06-28 11:15:03 +08:00
qset = Author . objects . raw ( query , params = params )
results = list ( qset )
2010-04-02 00:48:16 +08:00
self . assertProcessed ( Author , results , [ author ] )
2009-12-20 10:46:58 +08:00
self . assertNoAnnotations ( results )
self . assertEqual ( len ( results ) , 1 )
2013-06-28 11:15:03 +08:00
self . assertIsInstance ( repr ( qset ) , str )
@skipUnlessDBFeature ( ' supports_paramstyle_pyformat ' )
2014-07-08 07:08:42 +08:00
def test_pyformat_params ( self ) :
2013-06-28 11:15:03 +08:00
"""
Test passing optional query parameters
"""
query = " SELECT * FROM raw_query_author WHERE first_name = %(first)s "
author = Author . objects . all ( ) [ 2 ]
params = { ' first ' : author . first_name }
qset = Author . objects . raw ( query , params = params )
results = list ( qset )
self . assertProcessed ( Author , results , [ author ] )
self . assertNoAnnotations ( results )
self . assertEqual ( len ( results ) , 1 )
self . assertIsInstance ( repr ( qset ) , str )
2009-12-20 10:46:58 +08:00
2014-08-17 22:21:48 +08:00
def test_query_representation ( self ) :
"""
Test representation of raw query with parameters
"""
query = " SELECT * FROM raw_query_author WHERE last_name = %(last)s "
qset = Author . objects . raw ( query , { ' last ' : ' foo ' } )
self . assertEqual ( repr ( qset ) , " <RawQuerySet: SELECT * FROM raw_query_author WHERE last_name = foo> " )
self . assertEqual ( repr ( qset . query ) , " <RawQuery: SELECT * FROM raw_query_author WHERE last_name = foo> " )
query = " SELECT * FROM raw_query_author WHERE last_name = %s "
qset = Author . objects . raw ( query , { ' foo ' } )
self . assertEqual ( repr ( qset ) , " <RawQuerySet: SELECT * FROM raw_query_author WHERE last_name = foo> " )
self . assertEqual ( repr ( qset . query ) , " <RawQuery: SELECT * FROM raw_query_author WHERE last_name = foo> " )
2014-07-08 07:08:42 +08:00
def test_many_to_many ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test of a simple raw query against a model containing a m2m field
"""
query = " SELECT * FROM raw_query_reviewer "
reviewers = Reviewer . objects . all ( )
self . assertSuccessfulRawQuery ( Reviewer , query , reviewers )
2014-07-08 07:08:42 +08:00
def test_extra_conversions ( self ) :
2009-12-20 10:46:58 +08:00
"""
Test to insure that extra translations are ignored .
"""
query = " SELECT * FROM raw_query_author "
translations = { ' something ' : ' else ' }
authors = Author . objects . all ( )
self . assertSuccessfulRawQuery ( Author , query , authors , translations = translations )
2014-07-08 07:08:42 +08:00
def test_missing_fields ( self ) :
2009-12-20 10:46:58 +08:00
query = " SELECT id, first_name, dob FROM raw_query_author "
for author in Author . objects . raw ( query ) :
self . assertNotEqual ( author . first_name , None )
# last_name isn't given, but it will be retrieved on demand
self . assertNotEqual ( author . last_name , None )
2014-07-08 07:08:42 +08:00
def test_missing_fields_without_PK ( self ) :
2009-12-20 10:46:58 +08:00
query = " SELECT first_name, dob FROM raw_query_author "
try :
list ( Author . objects . raw ( query ) )
self . fail ( ' Query without primary key should fail ' )
except InvalidQuery :
pass
2014-07-08 07:08:42 +08:00
def test_annotations ( self ) :
2009-12-20 10:46:58 +08:00
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 "
expected_annotations = (
( ' book_count ' , 3 ) ,
( ' book_count ' , 0 ) ,
( ' book_count ' , 1 ) ,
( ' book_count ' , 0 ) ,
)
authors = Author . objects . all ( )
self . assertSuccessfulRawQuery ( Author , query , authors , expected_annotations )
2014-07-08 07:08:42 +08:00
def test_white_space_query ( self ) :
2009-12-20 10:46:58 +08:00
query = " SELECT * FROM raw_query_author "
authors = Author . objects . all ( )
self . assertSuccessfulRawQuery ( Author , query , authors )
2014-07-08 07:08:42 +08:00
def test_multiple_iterations ( self ) :
2009-12-20 10:46:58 +08:00
query = " SELECT * FROM raw_query_author "
normal_authors = Author . objects . all ( )
raw_authors = Author . objects . raw ( query )
# First Iteration
first_iterations = 0
for index , raw_author in enumerate ( raw_authors ) :
self . assertEqual ( normal_authors [ index ] , raw_author )
first_iterations + = 1
# Second Iteration
second_iterations = 0
for index , raw_author in enumerate ( raw_authors ) :
self . assertEqual ( normal_authors [ index ] , raw_author )
second_iterations + = 1
2010-02-23 13:22:12 +08:00
self . assertEqual ( first_iterations , second_iterations )
2014-07-08 07:08:42 +08:00
def test_get_item ( self ) :
2010-02-23 13:22:12 +08:00
# Indexing on RawQuerySets
query = " SELECT * FROM raw_query_author ORDER BY id ASC "
third_author = Author . objects . raw ( query ) [ 2 ]
self . assertEqual ( third_author . first_name , ' Bob ' )
first_two = Author . objects . raw ( query ) [ 0 : 2 ]
2011-03-03 23:04:39 +08:00
self . assertEqual ( len ( first_two ) , 2 )
2010-02-23 13:22:12 +08:00
2010-02-23 14:04:06 +08:00
self . assertRaises ( TypeError , lambda : Author . objects . raw ( query ) [ ' test ' ] )
2010-02-24 03:39:06 +08:00
def test_inheritance ( self ) :
# date is the end of the Cuban Missile Crisis, I have no idea when
2014-03-02 22:25:53 +08:00
# Wesley was born
2010-02-24 03:39:06 +08:00
f = FriendlyAuthor . objects . create ( first_name = " Wesley " , last_name = " Chun " ,
dob = date ( 1962 , 10 , 28 ) )
query = " SELECT * FROM raw_query_friendlyauthor "
self . assertEqual (
[ o . pk for o in FriendlyAuthor . objects . raw ( query ) ] , [ f . pk ]
)
2010-12-04 04:25:59 +08:00
def test_query_count ( self ) :
2013-12-09 01:20:06 +08:00
self . assertNumQueries ( 1 , list , Author . objects . raw ( " SELECT * FROM raw_query_author " ) )
2013-12-13 14:04:28 +08:00
def test_subquery_in_raw_sql ( self ) :
try :
2014-08-14 08:11:12 +08:00
list ( Book . objects . raw ( ' SELECT id FROM (SELECT * FROM raw_query_book WHERE paperback IS NOT NULL) sq ' ) )
2013-12-13 14:04:28 +08:00
except InvalidQuery :
self . fail ( " Using a subquery in a RawQuerySet raised InvalidQuery " )
2015-07-23 02:54:42 +08:00
def test_db_column_name_is_used_in_raw_query ( self ) :
"""
Regression test that ensures the ` column ` attribute on the field is
used to generate the list of fields included in the query , as opposed
to the ` attname ` . This is important when the primary key is a
ForeignKey field because ` attname ` and ` column ` are not necessarily the
same .
"""
b = BookFkAsPk . objects . create ( book = self . b1 )
self . assertEqual ( list ( BookFkAsPk . objects . raw ( ' SELECT not_the_default FROM raw_query_bookfkaspk ' ) ) , [ b ] )