Loading django/db/migrations/operations/special.py +2 −2 Original line number Diff line number Diff line Loading @@ -66,14 +66,14 @@ class RunSQL(Operation): def database_forwards(self, app_label, schema_editor, from_state, to_state): statements = schema_editor.connection.ops.prepare_sql_script(self.sql) for statement in statements: schema_editor.execute(statement) schema_editor.execute(statement, params=None) def database_backwards(self, app_label, schema_editor, from_state, to_state): if self.reverse_sql is None: raise NotImplementedError("You cannot reverse this operation") statements = schema_editor.connection.ops.prepare_sql_script(self.reverse_sql) for statement in statements: schema_editor.execute(statement) schema_editor.execute(statement, params=None) def describe(self): return "Raw SQL operation" Loading docs/ref/migration-operations.txt +5 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,11 @@ operation here so that the autodetector still has an up-to-date state of the model (otherwise, when you next run ``makemigrations``, it won't see any operation that adds that field and so will try to run it again). .. versionchanged:: 1.7.1 If you want to include literal percent signs in the query you don't need to double them anymore. .. _sqlparse: https://pypi.python.org/pypi/sqlparse RunPython Loading docs/releases/1.7.1.txt +3 −0 Original line number Diff line number Diff line Loading @@ -67,3 +67,6 @@ Bugfixes :meth:`~django.contrib.admin.InlineModelAdmin.get_min_num()` hooks to :class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin` (:ticket:`23539`). * Made ``migrations.RunSQL`` no longer require percent sign escaping. This is now consistent with ``cursor.execute()`` (:ticket:`23426`). tests/migrations/test_operations.py +15 −3 Original line number Diff line number Diff line Loading @@ -1156,10 +1156,18 @@ class OperationTests(OperationTestBase): # Create the operation operation = migrations.RunSQL( # Use a multi-line string with a comment to test splitting on SQLite and MySQL respectively "CREATE TABLE i_love_ponies (id int, special_thing int);\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 42); -- this is magic!\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 51);\n", "CREATE TABLE i_love_ponies (id int, special_thing varchar(15));\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 'i love ponies'); -- this is magic!\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 'i love django');\n" "UPDATE i_love_ponies SET special_thing = 'Ponies' WHERE special_thing LIKE '%%ponies';" "UPDATE i_love_ponies SET special_thing = 'Django' WHERE special_thing LIKE '%django';", # Run delete queries to test for parameter substitution failure # reported in #23426 "DELETE FROM i_love_ponies WHERE special_thing LIKE '%Django%';" "DELETE FROM i_love_ponies WHERE special_thing LIKE '%%Ponies%%';" "DROP TABLE i_love_ponies", state_operations=[migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))])], ) self.assertEqual(operation.describe(), "Raw SQL operation") Loading @@ -1177,6 +1185,10 @@ class OperationTests(OperationTestBase): with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM i_love_ponies") self.assertEqual(cursor.fetchall()[0][0], 2) cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Django'") self.assertEqual(cursor.fetchall()[0][0], 1) cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Ponies'") self.assertEqual(cursor.fetchall()[0][0], 1) # And test reversal self.assertTrue(operation.reversible) with connection.schema_editor() as editor: Loading Loading
django/db/migrations/operations/special.py +2 −2 Original line number Diff line number Diff line Loading @@ -66,14 +66,14 @@ class RunSQL(Operation): def database_forwards(self, app_label, schema_editor, from_state, to_state): statements = schema_editor.connection.ops.prepare_sql_script(self.sql) for statement in statements: schema_editor.execute(statement) schema_editor.execute(statement, params=None) def database_backwards(self, app_label, schema_editor, from_state, to_state): if self.reverse_sql is None: raise NotImplementedError("You cannot reverse this operation") statements = schema_editor.connection.ops.prepare_sql_script(self.reverse_sql) for statement in statements: schema_editor.execute(statement) schema_editor.execute(statement, params=None) def describe(self): return "Raw SQL operation" Loading
docs/ref/migration-operations.txt +5 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,11 @@ operation here so that the autodetector still has an up-to-date state of the model (otherwise, when you next run ``makemigrations``, it won't see any operation that adds that field and so will try to run it again). .. versionchanged:: 1.7.1 If you want to include literal percent signs in the query you don't need to double them anymore. .. _sqlparse: https://pypi.python.org/pypi/sqlparse RunPython Loading
docs/releases/1.7.1.txt +3 −0 Original line number Diff line number Diff line Loading @@ -67,3 +67,6 @@ Bugfixes :meth:`~django.contrib.admin.InlineModelAdmin.get_min_num()` hooks to :class:`~django.contrib.contenttypes.admin.GenericInlineModelAdmin` (:ticket:`23539`). * Made ``migrations.RunSQL`` no longer require percent sign escaping. This is now consistent with ``cursor.execute()`` (:ticket:`23426`).
tests/migrations/test_operations.py +15 −3 Original line number Diff line number Diff line Loading @@ -1156,10 +1156,18 @@ class OperationTests(OperationTestBase): # Create the operation operation = migrations.RunSQL( # Use a multi-line string with a comment to test splitting on SQLite and MySQL respectively "CREATE TABLE i_love_ponies (id int, special_thing int);\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 42); -- this is magic!\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 51);\n", "CREATE TABLE i_love_ponies (id int, special_thing varchar(15));\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 'i love ponies'); -- this is magic!\n" "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 'i love django');\n" "UPDATE i_love_ponies SET special_thing = 'Ponies' WHERE special_thing LIKE '%%ponies';" "UPDATE i_love_ponies SET special_thing = 'Django' WHERE special_thing LIKE '%django';", # Run delete queries to test for parameter substitution failure # reported in #23426 "DELETE FROM i_love_ponies WHERE special_thing LIKE '%Django%';" "DELETE FROM i_love_ponies WHERE special_thing LIKE '%%Ponies%%';" "DROP TABLE i_love_ponies", state_operations=[migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))])], ) self.assertEqual(operation.describe(), "Raw SQL operation") Loading @@ -1177,6 +1185,10 @@ class OperationTests(OperationTestBase): with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM i_love_ponies") self.assertEqual(cursor.fetchall()[0][0], 2) cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Django'") self.assertEqual(cursor.fetchall()[0][0], 1) cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Ponies'") self.assertEqual(cursor.fetchall()[0][0], 1) # And test reversal self.assertTrue(operation.reversible) with connection.schema_editor() as editor: Loading