2
0

test_operations.py 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  1. from __future__ import unicode_literals
  2. import unittest
  3. try:
  4. import sqlparse
  5. except ImportError:
  6. sqlparse = None
  7. from django import test
  8. from django.test import override_settings
  9. from django.db import connection, migrations, models, router
  10. from django.db.migrations.migration import Migration
  11. from django.db.migrations.state import ProjectState
  12. from django.db.models.fields import NOT_PROVIDED
  13. from django.db.transaction import atomic
  14. from django.db.utils import IntegrityError, DatabaseError
  15. from .test_base import MigrationTestBase
  16. class OperationTestBase(MigrationTestBase):
  17. """
  18. Common functions to help test operations.
  19. """
  20. def apply_operations(self, app_label, project_state, operations):
  21. migration = Migration('name', app_label)
  22. migration.operations = operations
  23. with connection.schema_editor() as editor:
  24. return migration.apply(project_state, editor)
  25. def unapply_operations(self, app_label, project_state, operations):
  26. migration = Migration('name', app_label)
  27. migration.operations = operations
  28. with connection.schema_editor() as editor:
  29. return migration.unapply(project_state, editor)
  30. def make_test_state(self, app_label, operation, **kwargs):
  31. """
  32. Makes a test state using set_up_test_model and returns the
  33. original state and the state after the migration is applied.
  34. """
  35. project_state = self.set_up_test_model(app_label, **kwargs)
  36. new_state = project_state.clone()
  37. operation.state_forwards(app_label, new_state)
  38. return project_state, new_state
  39. def set_up_test_model(self, app_label, second_model=False, third_model=False, related_model=False, mti_model=False, proxy_model=False, unique_together=False, options=False):
  40. """
  41. Creates a test model state and database table.
  42. """
  43. # Delete the tables if they already exist
  44. with connection.cursor() as cursor:
  45. # Start with ManyToMany tables
  46. try:
  47. cursor.execute("DROP TABLE %s_pony_stables" % app_label)
  48. except DatabaseError:
  49. pass
  50. try:
  51. cursor.execute("DROP TABLE %s_pony_vans" % app_label)
  52. except DatabaseError:
  53. pass
  54. # Then standard model tables
  55. try:
  56. cursor.execute("DROP TABLE %s_pony" % app_label)
  57. except DatabaseError:
  58. pass
  59. try:
  60. cursor.execute("DROP TABLE %s_stable" % app_label)
  61. except DatabaseError:
  62. pass
  63. try:
  64. cursor.execute("DROP TABLE %s_van" % app_label)
  65. except DatabaseError:
  66. pass
  67. # Make the "current" state
  68. model_options = {
  69. "swappable": "TEST_SWAP_MODEL",
  70. "unique_together": [["pink", "weight"]] if unique_together else [],
  71. }
  72. if options:
  73. model_options["permissions"] = [("can_groom", "Can groom")]
  74. operations = [migrations.CreateModel(
  75. "Pony",
  76. [
  77. ("id", models.AutoField(primary_key=True)),
  78. ("pink", models.IntegerField(default=3)),
  79. ("weight", models.FloatField()),
  80. ],
  81. options=model_options,
  82. )]
  83. if second_model:
  84. operations.append(migrations.CreateModel(
  85. "Stable",
  86. [
  87. ("id", models.AutoField(primary_key=True)),
  88. ]
  89. ))
  90. if third_model:
  91. operations.append(migrations.CreateModel(
  92. "Van",
  93. [
  94. ("id", models.AutoField(primary_key=True)),
  95. ]
  96. ))
  97. if related_model:
  98. operations.append(migrations.CreateModel(
  99. "Rider",
  100. [
  101. ("id", models.AutoField(primary_key=True)),
  102. ("pony", models.ForeignKey("Pony")),
  103. ("friend", models.ForeignKey("self"))
  104. ],
  105. ))
  106. if mti_model:
  107. operations.append(migrations.CreateModel(
  108. "ShetlandPony",
  109. fields=[
  110. ('pony_ptr', models.OneToOneField(
  111. auto_created=True,
  112. primary_key=True,
  113. to_field='id',
  114. serialize=False,
  115. to='Pony',
  116. )),
  117. ("cuteness", models.IntegerField(default=1)),
  118. ],
  119. bases=['%s.Pony' % app_label],
  120. ))
  121. if proxy_model:
  122. operations.append(migrations.CreateModel(
  123. "ProxyPony",
  124. fields=[],
  125. options={"proxy": True},
  126. bases=['%s.Pony' % app_label],
  127. ))
  128. return self.apply_operations(app_label, ProjectState(), operations)
  129. class OperationTests(OperationTestBase):
  130. """
  131. Tests running the operations and making sure they do what they say they do.
  132. Each test looks at their state changing, and then their database operation -
  133. both forwards and backwards.
  134. """
  135. def test_create_model(self):
  136. """
  137. Tests the CreateModel operation.
  138. Most other tests use this operation as part of setup, so check failures here first.
  139. """
  140. operation = migrations.CreateModel(
  141. "Pony",
  142. [
  143. ("id", models.AutoField(primary_key=True)),
  144. ("pink", models.IntegerField(default=1)),
  145. ],
  146. )
  147. self.assertEqual(operation.describe(), "Create model Pony")
  148. # Test the state alteration
  149. project_state = ProjectState()
  150. new_state = project_state.clone()
  151. operation.state_forwards("test_crmo", new_state)
  152. self.assertEqual(new_state.models["test_crmo", "pony"].name, "Pony")
  153. self.assertEqual(len(new_state.models["test_crmo", "pony"].fields), 2)
  154. # Test the database alteration
  155. self.assertTableNotExists("test_crmo_pony")
  156. with connection.schema_editor() as editor:
  157. operation.database_forwards("test_crmo", editor, project_state, new_state)
  158. self.assertTableExists("test_crmo_pony")
  159. # And test reversal
  160. with connection.schema_editor() as editor:
  161. operation.database_backwards("test_crmo", editor, new_state, project_state)
  162. self.assertTableNotExists("test_crmo_pony")
  163. # And deconstruction
  164. definition = operation.deconstruct()
  165. self.assertEqual(definition[0], "CreateModel")
  166. self.assertEqual(len(definition[1]), 2)
  167. self.assertEqual(len(definition[2]), 0)
  168. self.assertEqual(definition[1][0], "Pony")
  169. def test_create_model_with_unique_after(self):
  170. """
  171. Tests the CreateModel operation directly followed by an
  172. AlterUniqueTogether (bug #22844 - sqlite remake issues)
  173. """
  174. operation1 = migrations.CreateModel(
  175. "Pony",
  176. [
  177. ("id", models.AutoField(primary_key=True)),
  178. ("pink", models.IntegerField(default=1)),
  179. ],
  180. )
  181. operation2 = migrations.CreateModel(
  182. "Rider",
  183. [
  184. ("id", models.AutoField(primary_key=True)),
  185. ("number", models.IntegerField(default=1)),
  186. ("pony", models.ForeignKey("test_crmoua.Pony")),
  187. ],
  188. )
  189. operation3 = migrations.AlterUniqueTogether(
  190. "Rider",
  191. [
  192. ("number", "pony"),
  193. ],
  194. )
  195. # Test the database alteration
  196. project_state = ProjectState()
  197. self.assertTableNotExists("test_crmoua_pony")
  198. self.assertTableNotExists("test_crmoua_rider")
  199. with connection.schema_editor() as editor:
  200. new_state = project_state.clone()
  201. operation1.state_forwards("test_crmoua", new_state)
  202. operation1.database_forwards("test_crmoua", editor, project_state, new_state)
  203. project_state, new_state = new_state, new_state.clone()
  204. operation2.state_forwards("test_crmoua", new_state)
  205. operation2.database_forwards("test_crmoua", editor, project_state, new_state)
  206. project_state, new_state = new_state, new_state.clone()
  207. operation3.state_forwards("test_crmoua", new_state)
  208. operation3.database_forwards("test_crmoua", editor, project_state, new_state)
  209. self.assertTableExists("test_crmoua_pony")
  210. self.assertTableExists("test_crmoua_rider")
  211. def test_create_model_m2m(self):
  212. """
  213. Test the creation of a model with a ManyToMany field and the
  214. auto-created "through" model.
  215. """
  216. project_state = self.set_up_test_model("test_crmomm")
  217. operation = migrations.CreateModel(
  218. "Stable",
  219. [
  220. ("id", models.AutoField(primary_key=True)),
  221. ("ponies", models.ManyToManyField("Pony", related_name="stables"))
  222. ]
  223. )
  224. # Test the state alteration
  225. new_state = project_state.clone()
  226. operation.state_forwards("test_crmomm", new_state)
  227. # Test the database alteration
  228. self.assertTableNotExists("test_crmomm_stable_ponies")
  229. with connection.schema_editor() as editor:
  230. operation.database_forwards("test_crmomm", editor, project_state, new_state)
  231. self.assertTableExists("test_crmomm_stable")
  232. self.assertTableExists("test_crmomm_stable_ponies")
  233. self.assertColumnNotExists("test_crmomm_stable", "ponies")
  234. # Make sure the M2M field actually works
  235. with atomic():
  236. new_apps = new_state.render()
  237. Pony = new_apps.get_model("test_crmomm", "Pony")
  238. Stable = new_apps.get_model("test_crmomm", "Stable")
  239. stable = Stable.objects.create()
  240. p1 = Pony.objects.create(pink=False, weight=4.55)
  241. p2 = Pony.objects.create(pink=True, weight=5.43)
  242. stable.ponies.add(p1, p2)
  243. self.assertEqual(stable.ponies.count(), 2)
  244. stable.ponies.all().delete()
  245. # And test reversal
  246. with connection.schema_editor() as editor:
  247. operation.database_backwards("test_crmomm", editor, new_state, project_state)
  248. self.assertTableNotExists("test_crmomm_stable")
  249. self.assertTableNotExists("test_crmomm_stable_ponies")
  250. def test_create_model_inheritance(self):
  251. """
  252. Tests the CreateModel operation on a multi-table inheritance setup.
  253. """
  254. project_state = self.set_up_test_model("test_crmoih")
  255. # Test the state alteration
  256. operation = migrations.CreateModel(
  257. "ShetlandPony",
  258. [
  259. ('pony_ptr', models.OneToOneField(
  260. auto_created=True,
  261. primary_key=True,
  262. to_field='id',
  263. serialize=False,
  264. to='test_crmoih.Pony',
  265. )),
  266. ("cuteness", models.IntegerField(default=1)),
  267. ],
  268. )
  269. new_state = project_state.clone()
  270. operation.state_forwards("test_crmoih", new_state)
  271. self.assertIn(("test_crmoih", "shetlandpony"), new_state.models)
  272. # Test the database alteration
  273. self.assertTableNotExists("test_crmoih_shetlandpony")
  274. with connection.schema_editor() as editor:
  275. operation.database_forwards("test_crmoih", editor, project_state, new_state)
  276. self.assertTableExists("test_crmoih_shetlandpony")
  277. # And test reversal
  278. with connection.schema_editor() as editor:
  279. operation.database_backwards("test_crmoih", editor, new_state, project_state)
  280. self.assertTableNotExists("test_crmoih_shetlandpony")
  281. def test_create_proxy_model(self):
  282. """
  283. Tests that CreateModel ignores proxy models.
  284. """
  285. project_state = self.set_up_test_model("test_crprmo")
  286. # Test the state alteration
  287. operation = migrations.CreateModel(
  288. "ProxyPony",
  289. [],
  290. options={"proxy": True},
  291. bases=("test_crprmo.Pony", ),
  292. )
  293. self.assertEqual(operation.describe(), "Create proxy model ProxyPony")
  294. new_state = project_state.clone()
  295. operation.state_forwards("test_crprmo", new_state)
  296. self.assertIn(("test_crprmo", "proxypony"), new_state.models)
  297. # Test the database alteration
  298. self.assertTableNotExists("test_crprmo_proxypony")
  299. self.assertTableExists("test_crprmo_pony")
  300. with connection.schema_editor() as editor:
  301. operation.database_forwards("test_crprmo", editor, project_state, new_state)
  302. self.assertTableNotExists("test_crprmo_proxypony")
  303. self.assertTableExists("test_crprmo_pony")
  304. # And test reversal
  305. with connection.schema_editor() as editor:
  306. operation.database_backwards("test_crprmo", editor, new_state, project_state)
  307. self.assertTableNotExists("test_crprmo_proxypony")
  308. self.assertTableExists("test_crprmo_pony")
  309. def test_create_unmanaged_model(self):
  310. """
  311. Tests that CreateModel ignores unmanaged models.
  312. """
  313. project_state = self.set_up_test_model("test_crummo")
  314. # Test the state alteration
  315. operation = migrations.CreateModel(
  316. "UnmanagedPony",
  317. [],
  318. options={"proxy": True},
  319. bases=("test_crummo.Pony", ),
  320. )
  321. self.assertEqual(operation.describe(), "Create proxy model UnmanagedPony")
  322. new_state = project_state.clone()
  323. operation.state_forwards("test_crummo", new_state)
  324. self.assertIn(("test_crummo", "unmanagedpony"), new_state.models)
  325. # Test the database alteration
  326. self.assertTableNotExists("test_crummo_unmanagedpony")
  327. self.assertTableExists("test_crummo_pony")
  328. with connection.schema_editor() as editor:
  329. operation.database_forwards("test_crummo", editor, project_state, new_state)
  330. self.assertTableNotExists("test_crummo_unmanagedpony")
  331. self.assertTableExists("test_crummo_pony")
  332. # And test reversal
  333. with connection.schema_editor() as editor:
  334. operation.database_backwards("test_crummo", editor, new_state, project_state)
  335. self.assertTableNotExists("test_crummo_unmanagedpony")
  336. self.assertTableExists("test_crummo_pony")
  337. def test_delete_model(self):
  338. """
  339. Tests the DeleteModel operation.
  340. """
  341. project_state = self.set_up_test_model("test_dlmo")
  342. # Test the state alteration
  343. operation = migrations.DeleteModel("Pony")
  344. self.assertEqual(operation.describe(), "Delete model Pony")
  345. new_state = project_state.clone()
  346. operation.state_forwards("test_dlmo", new_state)
  347. self.assertNotIn(("test_dlmo", "pony"), new_state.models)
  348. # Test the database alteration
  349. self.assertTableExists("test_dlmo_pony")
  350. with connection.schema_editor() as editor:
  351. operation.database_forwards("test_dlmo", editor, project_state, new_state)
  352. self.assertTableNotExists("test_dlmo_pony")
  353. # And test reversal
  354. with connection.schema_editor() as editor:
  355. operation.database_backwards("test_dlmo", editor, new_state, project_state)
  356. self.assertTableExists("test_dlmo_pony")
  357. def test_delete_proxy_model(self):
  358. """
  359. Tests the DeleteModel operation ignores proxy models.
  360. """
  361. project_state = self.set_up_test_model("test_dlprmo", proxy_model=True)
  362. # Test the state alteration
  363. operation = migrations.DeleteModel("ProxyPony")
  364. new_state = project_state.clone()
  365. operation.state_forwards("test_dlprmo", new_state)
  366. self.assertIn(("test_dlprmo", "proxypony"), project_state.models)
  367. self.assertNotIn(("test_dlprmo", "proxypony"), new_state.models)
  368. # Test the database alteration
  369. self.assertTableExists("test_dlprmo_pony")
  370. self.assertTableNotExists("test_dlprmo_proxypony")
  371. with connection.schema_editor() as editor:
  372. operation.database_forwards("test_dlprmo", editor, project_state, new_state)
  373. self.assertTableExists("test_dlprmo_pony")
  374. self.assertTableNotExists("test_dlprmo_proxypony")
  375. # And test reversal
  376. with connection.schema_editor() as editor:
  377. operation.database_backwards("test_dlprmo", editor, new_state, project_state)
  378. self.assertTableExists("test_dlprmo_pony")
  379. self.assertTableNotExists("test_dlprmo_proxypony")
  380. def test_rename_model(self):
  381. """
  382. Tests the RenameModel operation.
  383. """
  384. project_state = self.set_up_test_model("test_rnmo", related_model=True)
  385. # Test the state alteration
  386. operation = migrations.RenameModel("Pony", "Horse")
  387. self.assertEqual(operation.describe(), "Rename model Pony to Horse")
  388. new_state = project_state.clone()
  389. operation.state_forwards("test_rnmo", new_state)
  390. self.assertNotIn(("test_rnmo", "pony"), new_state.models)
  391. self.assertIn(("test_rnmo", "horse"), new_state.models)
  392. # Remember, RenameModel also repoints all incoming FKs and M2Ms
  393. self.assertEqual("test_rnmo.Horse", new_state.models["test_rnmo", "rider"].fields[1][1].rel.to)
  394. # Test the database alteration
  395. self.assertTableExists("test_rnmo_pony")
  396. self.assertTableNotExists("test_rnmo_horse")
  397. if connection.features.supports_foreign_keys:
  398. self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id"))
  399. self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id"))
  400. with connection.schema_editor() as editor:
  401. operation.database_forwards("test_rnmo", editor, project_state, new_state)
  402. self.assertTableNotExists("test_rnmo_pony")
  403. self.assertTableExists("test_rnmo_horse")
  404. if connection.features.supports_foreign_keys:
  405. self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id"))
  406. self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id"))
  407. # And test reversal
  408. with connection.schema_editor() as editor:
  409. operation.database_backwards("test_rnmo", editor, new_state, project_state)
  410. self.assertTableExists("test_rnmo_pony")
  411. self.assertTableNotExists("test_rnmo_horse")
  412. if connection.features.supports_foreign_keys:
  413. self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id"))
  414. self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id"))
  415. def test_rename_model_with_self_referential_fk(self):
  416. """
  417. Tests the RenameModel operation on model with self referential FK.
  418. """
  419. project_state = self.set_up_test_model("test_rmwsrf", related_model=True)
  420. # Test the state alteration
  421. operation = migrations.RenameModel("Rider", "HorseRider")
  422. self.assertEqual(operation.describe(), "Rename model Rider to HorseRider")
  423. new_state = project_state.clone()
  424. operation.state_forwards("test_rmwsrf", new_state)
  425. self.assertNotIn(("test_rmwsrf", "rider"), new_state.models)
  426. self.assertIn(("test_rmwsrf", "horserider"), new_state.models)
  427. # Remember, RenameModel also repoints all incoming FKs and M2Ms
  428. self.assertEqual("test_rmwsrf.HorseRider", new_state.models["test_rmwsrf", "horserider"].fields[2][1].rel.to)
  429. # Test the database alteration
  430. self.assertTableExists("test_rmwsrf_rider")
  431. self.assertTableNotExists("test_rmwsrf_horserider")
  432. if connection.features.supports_foreign_keys:
  433. self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
  434. self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
  435. with connection.schema_editor() as editor:
  436. operation.database_forwards("test_rmwsrf", editor, project_state, new_state)
  437. self.assertTableNotExists("test_rmwsrf_rider")
  438. self.assertTableExists("test_rmwsrf_horserider")
  439. if connection.features.supports_foreign_keys:
  440. self.assertFKNotExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_rider", "id"))
  441. self.assertFKExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
  442. # And test reversal
  443. with connection.schema_editor() as editor:
  444. operation.database_backwards("test_rmwsrf", editor, new_state, project_state)
  445. self.assertTableExists("test_rmwsrf_rider")
  446. self.assertTableNotExists("test_rmwsrf_horserider")
  447. if connection.features.supports_foreign_keys:
  448. self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
  449. self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
  450. def test_rename_model_with_self_referential_m2m(self):
  451. app_label = "test_rename_model_with_self_referential_m2m"
  452. project_state = self.apply_operations(app_label, ProjectState(), operations=[
  453. migrations.CreateModel("ReflexivePony", fields=[
  454. ("ponies", models.ManyToManyField("self")),
  455. ]),
  456. ])
  457. project_state = self.apply_operations(app_label, project_state, operations=[
  458. migrations.RenameModel("ReflexivePony", "ReflexivePony2"),
  459. ])
  460. apps = project_state.render()
  461. Pony = apps.get_model(app_label, "ReflexivePony2")
  462. pony = Pony.objects.create()
  463. pony.ponies.add(pony)
  464. def test_add_field(self):
  465. """
  466. Tests the AddField operation.
  467. """
  468. # Test the state alteration
  469. operation = migrations.AddField(
  470. "Pony",
  471. "height",
  472. models.FloatField(null=True, default=5),
  473. )
  474. self.assertEqual(operation.describe(), "Add field height to Pony")
  475. project_state, new_state = self.make_test_state("test_adfl", operation)
  476. self.assertEqual(len(new_state.models["test_adfl", "pony"].fields), 4)
  477. field = [
  478. f for n, f in new_state.models["test_adfl", "pony"].fields
  479. if n == "height"
  480. ][0]
  481. self.assertEqual(field.default, 5)
  482. # Test the database alteration
  483. self.assertColumnNotExists("test_adfl_pony", "height")
  484. with connection.schema_editor() as editor:
  485. operation.database_forwards("test_adfl", editor, project_state, new_state)
  486. self.assertColumnExists("test_adfl_pony", "height")
  487. # And test reversal
  488. with connection.schema_editor() as editor:
  489. operation.database_backwards("test_adfl", editor, new_state, project_state)
  490. self.assertColumnNotExists("test_adfl_pony", "height")
  491. def test_add_charfield(self):
  492. """
  493. Tests the AddField operation on TextField.
  494. """
  495. project_state = self.set_up_test_model("test_adchfl")
  496. new_apps = project_state.render()
  497. Pony = new_apps.get_model("test_adchfl", "Pony")
  498. pony = Pony.objects.create(weight=42)
  499. new_state = self.apply_operations("test_adchfl", project_state, [
  500. migrations.AddField(
  501. "Pony",
  502. "text",
  503. models.CharField(max_length=10, default="some text"),
  504. ),
  505. migrations.AddField(
  506. "Pony",
  507. "empty",
  508. models.CharField(max_length=10, default=""),
  509. ),
  510. # If not properly quoted digits would be interpreted as an int.
  511. migrations.AddField(
  512. "Pony",
  513. "digits",
  514. models.CharField(max_length=10, default="42"),
  515. ),
  516. # Manual quoting is fragile and could trip on quotes. Refs #xyz.
  517. migrations.AddField(
  518. "Pony",
  519. "quotes",
  520. models.CharField(max_length=10, default='"\'"'),
  521. ),
  522. ])
  523. new_apps = new_state.render()
  524. Pony = new_apps.get_model("test_adchfl", "Pony")
  525. pony = Pony.objects.get(pk=pony.pk)
  526. self.assertEqual(pony.text, "some text")
  527. self.assertEqual(pony.empty, "")
  528. self.assertEqual(pony.digits, "42")
  529. self.assertEqual(pony.quotes, '"\'"')
  530. def test_add_textfield(self):
  531. """
  532. Tests the AddField operation on TextField.
  533. """
  534. project_state = self.set_up_test_model("test_adtxtfl")
  535. new_apps = project_state.render()
  536. Pony = new_apps.get_model("test_adtxtfl", "Pony")
  537. pony = Pony.objects.create(weight=42)
  538. new_state = self.apply_operations("test_adtxtfl", project_state, [
  539. migrations.AddField(
  540. "Pony",
  541. "text",
  542. models.TextField(default="some text"),
  543. ),
  544. migrations.AddField(
  545. "Pony",
  546. "empty",
  547. models.TextField(default=""),
  548. ),
  549. # If not properly quoted digits would be interpreted as an int.
  550. migrations.AddField(
  551. "Pony",
  552. "digits",
  553. models.TextField(default="42"),
  554. ),
  555. # Manual quoting is fragile and could trip on quotes. Refs #xyz.
  556. migrations.AddField(
  557. "Pony",
  558. "quotes",
  559. models.TextField(default='"\'"'),
  560. ),
  561. ])
  562. new_apps = new_state.render()
  563. Pony = new_apps.get_model("test_adtxtfl", "Pony")
  564. pony = Pony.objects.get(pk=pony.pk)
  565. self.assertEqual(pony.text, "some text")
  566. self.assertEqual(pony.empty, "")
  567. self.assertEqual(pony.digits, "42")
  568. self.assertEqual(pony.quotes, '"\'"')
  569. @test.skipUnlessDBFeature('supports_binary_field')
  570. def test_add_binaryfield(self):
  571. """
  572. Tests the AddField operation on TextField/BinaryField.
  573. """
  574. project_state = self.set_up_test_model("test_adbinfl")
  575. new_apps = project_state.render()
  576. Pony = new_apps.get_model("test_adbinfl", "Pony")
  577. pony = Pony.objects.create(weight=42)
  578. new_state = self.apply_operations("test_adbinfl", project_state, [
  579. migrations.AddField(
  580. "Pony",
  581. "blob",
  582. models.BinaryField(default=b"some text"),
  583. ),
  584. migrations.AddField(
  585. "Pony",
  586. "empty",
  587. models.BinaryField(default=b""),
  588. ),
  589. # If not properly quoted digits would be interpreted as an int.
  590. migrations.AddField(
  591. "Pony",
  592. "digits",
  593. models.BinaryField(default=b"42"),
  594. ),
  595. # Manual quoting is fragile and could trip on quotes. Refs #xyz.
  596. migrations.AddField(
  597. "Pony",
  598. "quotes",
  599. models.BinaryField(default=b'"\'"'),
  600. ),
  601. ])
  602. new_apps = new_state.render()
  603. Pony = new_apps.get_model("test_adbinfl", "Pony")
  604. pony = Pony.objects.get(pk=pony.pk)
  605. # SQLite returns buffer/memoryview, cast to bytes for checking.
  606. self.assertEqual(bytes(pony.blob), b"some text")
  607. self.assertEqual(bytes(pony.empty), b"")
  608. self.assertEqual(bytes(pony.digits), b"42")
  609. self.assertEqual(bytes(pony.quotes), b'"\'"')
  610. def test_column_name_quoting(self):
  611. """
  612. Column names that are SQL keywords shouldn't cause problems when used
  613. in migrations (#22168).
  614. """
  615. project_state = self.set_up_test_model("test_regr22168")
  616. operation = migrations.AddField(
  617. "Pony",
  618. "order",
  619. models.IntegerField(default=0),
  620. )
  621. new_state = project_state.clone()
  622. operation.state_forwards("test_regr22168", new_state)
  623. with connection.schema_editor() as editor:
  624. operation.database_forwards("test_regr22168", editor, project_state, new_state)
  625. self.assertColumnExists("test_regr22168_pony", "order")
  626. def test_add_field_preserve_default(self):
  627. """
  628. Tests the AddField operation's state alteration
  629. when preserve_default = False.
  630. """
  631. project_state = self.set_up_test_model("test_adflpd")
  632. # Test the state alteration
  633. operation = migrations.AddField(
  634. "Pony",
  635. "height",
  636. models.FloatField(null=True, default=4),
  637. preserve_default=False,
  638. )
  639. new_state = project_state.clone()
  640. operation.state_forwards("test_adflpd", new_state)
  641. self.assertEqual(len(new_state.models["test_adflpd", "pony"].fields), 4)
  642. field = [
  643. f for n, f in new_state.models["test_adflpd", "pony"].fields
  644. if n == "height"
  645. ][0]
  646. self.assertEqual(field.default, NOT_PROVIDED)
  647. # Test the database alteration
  648. project_state.render().get_model("test_adflpd", "pony").objects.create(
  649. weight=4,
  650. )
  651. self.assertColumnNotExists("test_adflpd_pony", "height")
  652. with connection.schema_editor() as editor:
  653. operation.database_forwards("test_adflpd", editor, project_state, new_state)
  654. self.assertColumnExists("test_adflpd_pony", "height")
  655. def test_add_field_m2m(self):
  656. """
  657. Tests the AddField operation with a ManyToManyField.
  658. """
  659. project_state = self.set_up_test_model("test_adflmm", second_model=True)
  660. # Test the state alteration
  661. operation = migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies"))
  662. new_state = project_state.clone()
  663. operation.state_forwards("test_adflmm", new_state)
  664. self.assertEqual(len(new_state.models["test_adflmm", "pony"].fields), 4)
  665. # Test the database alteration
  666. self.assertTableNotExists("test_adflmm_pony_stables")
  667. with connection.schema_editor() as editor:
  668. operation.database_forwards("test_adflmm", editor, project_state, new_state)
  669. self.assertTableExists("test_adflmm_pony_stables")
  670. self.assertColumnNotExists("test_adflmm_pony", "stables")
  671. # Make sure the M2M field actually works
  672. with atomic():
  673. new_apps = new_state.render()
  674. Pony = new_apps.get_model("test_adflmm", "Pony")
  675. p = Pony.objects.create(pink=False, weight=4.55)
  676. p.stables.create()
  677. self.assertEqual(p.stables.count(), 1)
  678. p.stables.all().delete()
  679. # And test reversal
  680. with connection.schema_editor() as editor:
  681. operation.database_backwards("test_adflmm", editor, new_state, project_state)
  682. self.assertTableNotExists("test_adflmm_pony_stables")
  683. def test_alter_field_m2m(self):
  684. project_state = self.set_up_test_model("test_alflmm", second_model=True)
  685. project_state = self.apply_operations("test_alflmm", project_state, operations=[
  686. migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies"))
  687. ])
  688. new_apps = project_state.render()
  689. Pony = new_apps.get_model("test_alflmm", "Pony")
  690. self.assertFalse(Pony._meta.get_field('stables').blank)
  691. project_state = self.apply_operations("test_alflmm", project_state, operations=[
  692. migrations.AlterField("Pony", "stables", models.ManyToManyField(to="Stable", related_name="ponies", blank=True))
  693. ])
  694. new_apps = project_state.render()
  695. Pony = new_apps.get_model("test_alflmm", "Pony")
  696. self.assertTrue(Pony._meta.get_field('stables').blank)
  697. def test_repoint_field_m2m(self):
  698. project_state = self.set_up_test_model("test_alflmm", second_model=True, third_model=True)
  699. project_state = self.apply_operations("test_alflmm", project_state, operations=[
  700. migrations.AddField("Pony", "places", models.ManyToManyField("Stable", related_name="ponies"))
  701. ])
  702. new_apps = project_state.render()
  703. Pony = new_apps.get_model("test_alflmm", "Pony")
  704. project_state = self.apply_operations("test_alflmm", project_state, operations=[
  705. migrations.AlterField("Pony", "places", models.ManyToManyField(to="Van", related_name="ponies"))
  706. ])
  707. # Ensure the new field actually works
  708. new_apps = project_state.render()
  709. Pony = new_apps.get_model("test_alflmm", "Pony")
  710. p = Pony.objects.create(pink=False, weight=4.55)
  711. p.places.create()
  712. self.assertEqual(p.places.count(), 1)
  713. p.places.all().delete()
  714. def test_remove_field_m2m(self):
  715. project_state = self.set_up_test_model("test_rmflmm", second_model=True)
  716. project_state = self.apply_operations("test_rmflmm", project_state, operations=[
  717. migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies"))
  718. ])
  719. self.assertTableExists("test_rmflmm_pony_stables")
  720. operations = [migrations.RemoveField("Pony", "stables")]
  721. self.apply_operations("test_rmflmm", project_state, operations=operations)
  722. self.assertTableNotExists("test_rmflmm_pony_stables")
  723. # And test reversal
  724. self.unapply_operations("test_rmflmm", project_state, operations=operations)
  725. self.assertTableExists("test_rmflmm_pony_stables")
  726. def test_remove_field_m2m_with_through(self):
  727. project_state = self.set_up_test_model("test_rmflmmwt", second_model=True)
  728. self.assertTableNotExists("test_rmflmmwt_ponystables")
  729. project_state = self.apply_operations("test_rmflmmwt", project_state, operations=[
  730. migrations.CreateModel("PonyStables", fields=[
  731. ("pony", models.ForeignKey('test_rmflmmwt.Pony')),
  732. ("stable", models.ForeignKey('test_rmflmmwt.Stable')),
  733. ]),
  734. migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies", through='test_rmflmmwt.PonyStables'))
  735. ])
  736. self.assertTableExists("test_rmflmmwt_ponystables")
  737. operations = [migrations.RemoveField("Pony", "stables")]
  738. self.apply_operations("test_rmflmmwt", project_state, operations=operations)
  739. def test_remove_field(self):
  740. """
  741. Tests the RemoveField operation.
  742. """
  743. project_state = self.set_up_test_model("test_rmfl")
  744. # Test the state alteration
  745. operation = migrations.RemoveField("Pony", "pink")
  746. self.assertEqual(operation.describe(), "Remove field pink from Pony")
  747. new_state = project_state.clone()
  748. operation.state_forwards("test_rmfl", new_state)
  749. self.assertEqual(len(new_state.models["test_rmfl", "pony"].fields), 2)
  750. # Test the database alteration
  751. self.assertColumnExists("test_rmfl_pony", "pink")
  752. with connection.schema_editor() as editor:
  753. operation.database_forwards("test_rmfl", editor, project_state, new_state)
  754. self.assertColumnNotExists("test_rmfl_pony", "pink")
  755. # And test reversal
  756. with connection.schema_editor() as editor:
  757. operation.database_backwards("test_rmfl", editor, new_state, project_state)
  758. self.assertColumnExists("test_rmfl_pony", "pink")
  759. def test_remove_fk(self):
  760. """
  761. Tests the RemoveField operation on a foreign key.
  762. """
  763. project_state = self.set_up_test_model("test_rfk", related_model=True)
  764. self.assertColumnExists("test_rfk_rider", "pony_id")
  765. operation = migrations.RemoveField("Rider", "pony")
  766. new_state = project_state.clone()
  767. operation.state_forwards("test_rfk", new_state)
  768. with connection.schema_editor() as editor:
  769. operation.database_forwards("test_rfk", editor, project_state, new_state)
  770. self.assertColumnNotExists("test_rfk_rider", "pony_id")
  771. with connection.schema_editor() as editor:
  772. operation.database_backwards("test_rfk", editor, new_state, project_state)
  773. self.assertColumnExists("test_rfk_rider", "pony_id")
  774. def test_alter_model_table(self):
  775. """
  776. Tests the AlterModelTable operation.
  777. """
  778. project_state = self.set_up_test_model("test_almota")
  779. # Test the state alteration
  780. operation = migrations.AlterModelTable("Pony", "test_almota_pony_2")
  781. self.assertEqual(operation.describe(), "Rename table for Pony to test_almota_pony_2")
  782. new_state = project_state.clone()
  783. operation.state_forwards("test_almota", new_state)
  784. self.assertEqual(new_state.models["test_almota", "pony"].options["db_table"], "test_almota_pony_2")
  785. # Test the database alteration
  786. self.assertTableExists("test_almota_pony")
  787. self.assertTableNotExists("test_almota_pony_2")
  788. with connection.schema_editor() as editor:
  789. operation.database_forwards("test_almota", editor, project_state, new_state)
  790. self.assertTableNotExists("test_almota_pony")
  791. self.assertTableExists("test_almota_pony_2")
  792. # And test reversal
  793. with connection.schema_editor() as editor:
  794. operation.database_backwards("test_almota", editor, new_state, project_state)
  795. self.assertTableExists("test_almota_pony")
  796. self.assertTableNotExists("test_almota_pony_2")
  797. def test_alter_model_table_noop(self):
  798. """
  799. Tests the AlterModelTable operation if the table name is not changed.
  800. """
  801. project_state = self.set_up_test_model("test_almota")
  802. # Test the state alteration
  803. operation = migrations.AlterModelTable("Pony", "test_almota_pony")
  804. new_state = project_state.clone()
  805. operation.state_forwards("test_almota", new_state)
  806. self.assertEqual(new_state.models["test_almota", "pony"].options["db_table"], "test_almota_pony")
  807. # Test the database alteration
  808. self.assertTableExists("test_almota_pony")
  809. with connection.schema_editor() as editor:
  810. operation.database_forwards("test_almota", editor, project_state, new_state)
  811. self.assertTableExists("test_almota_pony")
  812. # And test reversal
  813. with connection.schema_editor() as editor:
  814. operation.database_backwards("test_almota", editor, new_state, project_state)
  815. self.assertTableExists("test_almota_pony")
  816. def test_alter_field(self):
  817. """
  818. Tests the AlterField operation.
  819. """
  820. project_state = self.set_up_test_model("test_alfl")
  821. # Test the state alteration
  822. operation = migrations.AlterField("Pony", "pink", models.IntegerField(null=True))
  823. self.assertEqual(operation.describe(), "Alter field pink on Pony")
  824. new_state = project_state.clone()
  825. operation.state_forwards("test_alfl", new_state)
  826. self.assertEqual(project_state.models["test_alfl", "pony"].get_field_by_name("pink").null, False)
  827. self.assertEqual(new_state.models["test_alfl", "pony"].get_field_by_name("pink").null, True)
  828. # Test the database alteration
  829. self.assertColumnNotNull("test_alfl_pony", "pink")
  830. with connection.schema_editor() as editor:
  831. operation.database_forwards("test_alfl", editor, project_state, new_state)
  832. self.assertColumnNull("test_alfl_pony", "pink")
  833. # And test reversal
  834. with connection.schema_editor() as editor:
  835. operation.database_backwards("test_alfl", editor, new_state, project_state)
  836. self.assertColumnNotNull("test_alfl_pony", "pink")
  837. def test_alter_field_pk(self):
  838. """
  839. Tests the AlterField operation on primary keys (for things like PostgreSQL's SERIAL weirdness)
  840. """
  841. project_state = self.set_up_test_model("test_alflpk")
  842. # Test the state alteration
  843. operation = migrations.AlterField("Pony", "id", models.IntegerField(primary_key=True))
  844. new_state = project_state.clone()
  845. operation.state_forwards("test_alflpk", new_state)
  846. self.assertIsInstance(project_state.models["test_alflpk", "pony"].get_field_by_name("id"), models.AutoField)
  847. self.assertIsInstance(new_state.models["test_alflpk", "pony"].get_field_by_name("id"), models.IntegerField)
  848. # Test the database alteration
  849. with connection.schema_editor() as editor:
  850. operation.database_forwards("test_alflpk", editor, project_state, new_state)
  851. # And test reversal
  852. with connection.schema_editor() as editor:
  853. operation.database_backwards("test_alflpk", editor, new_state, project_state)
  854. @unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
  855. def test_alter_field_pk_fk(self):
  856. """
  857. Tests the AlterField operation on primary keys changes any FKs pointing to it.
  858. """
  859. project_state = self.set_up_test_model("test_alflpkfk", related_model=True)
  860. # Test the state alteration
  861. operation = migrations.AlterField("Pony", "id", models.FloatField(primary_key=True))
  862. new_state = project_state.clone()
  863. operation.state_forwards("test_alflpkfk", new_state)
  864. self.assertIsInstance(project_state.models["test_alflpkfk", "pony"].get_field_by_name("id"), models.AutoField)
  865. self.assertIsInstance(new_state.models["test_alflpkfk", "pony"].get_field_by_name("id"), models.FloatField)
  866. def assertIdTypeEqualsFkType():
  867. with connection.cursor() as cursor:
  868. id_type = [c.type_code for c in connection.introspection.get_table_description(cursor, "test_alflpkfk_pony") if c.name == "id"][0]
  869. fk_type = [c.type_code for c in connection.introspection.get_table_description(cursor, "test_alflpkfk_rider") if c.name == "pony_id"][0]
  870. self.assertEqual(id_type, fk_type)
  871. assertIdTypeEqualsFkType()
  872. # Test the database alteration
  873. with connection.schema_editor() as editor:
  874. operation.database_forwards("test_alflpkfk", editor, project_state, new_state)
  875. assertIdTypeEqualsFkType()
  876. # And test reversal
  877. with connection.schema_editor() as editor:
  878. operation.database_backwards("test_alflpkfk", editor, new_state, project_state)
  879. assertIdTypeEqualsFkType()
  880. def test_rename_field(self):
  881. """
  882. Tests the RenameField operation.
  883. """
  884. project_state = self.set_up_test_model("test_rnfl", unique_together=True)
  885. # Test the state alteration
  886. operation = migrations.RenameField("Pony", "pink", "blue")
  887. self.assertEqual(operation.describe(), "Rename field pink on Pony to blue")
  888. new_state = project_state.clone()
  889. operation.state_forwards("test_rnfl", new_state)
  890. self.assertIn("blue", [n for n, f in new_state.models["test_rnfl", "pony"].fields])
  891. self.assertNotIn("pink", [n for n, f in new_state.models["test_rnfl", "pony"].fields])
  892. # Make sure the unique_together has the renamed column too
  893. self.assertIn("blue", new_state.models["test_rnfl", "pony"].options['unique_together'][0])
  894. self.assertNotIn("pink", new_state.models["test_rnfl", "pony"].options['unique_together'][0])
  895. # Test the database alteration
  896. self.assertColumnExists("test_rnfl_pony", "pink")
  897. self.assertColumnNotExists("test_rnfl_pony", "blue")
  898. with connection.schema_editor() as editor:
  899. operation.database_forwards("test_rnfl", editor, project_state, new_state)
  900. self.assertColumnExists("test_rnfl_pony", "blue")
  901. self.assertColumnNotExists("test_rnfl_pony", "pink")
  902. # Ensure the unique constraint has been ported over
  903. with connection.cursor() as cursor:
  904. cursor.execute("INSERT INTO test_rnfl_pony (blue, weight) VALUES (1, 1)")
  905. with self.assertRaises(IntegrityError):
  906. with atomic():
  907. cursor.execute("INSERT INTO test_rnfl_pony (blue, weight) VALUES (1, 1)")
  908. cursor.execute("DELETE FROM test_rnfl_pony")
  909. # And test reversal
  910. with connection.schema_editor() as editor:
  911. operation.database_backwards("test_rnfl", editor, new_state, project_state)
  912. self.assertColumnExists("test_rnfl_pony", "pink")
  913. self.assertColumnNotExists("test_rnfl_pony", "blue")
  914. def test_alter_unique_together(self):
  915. """
  916. Tests the AlterUniqueTogether operation.
  917. """
  918. project_state = self.set_up_test_model("test_alunto")
  919. # Test the state alteration
  920. operation = migrations.AlterUniqueTogether("Pony", [("pink", "weight")])
  921. self.assertEqual(operation.describe(), "Alter unique_together for Pony (1 constraint(s))")
  922. new_state = project_state.clone()
  923. operation.state_forwards("test_alunto", new_state)
  924. self.assertEqual(len(project_state.models["test_alunto", "pony"].options.get("unique_together", set())), 0)
  925. self.assertEqual(len(new_state.models["test_alunto", "pony"].options.get("unique_together", set())), 1)
  926. # Make sure we can insert duplicate rows
  927. with connection.cursor() as cursor:
  928. cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)")
  929. cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)")
  930. cursor.execute("DELETE FROM test_alunto_pony")
  931. # Test the database alteration
  932. with connection.schema_editor() as editor:
  933. operation.database_forwards("test_alunto", editor, project_state, new_state)
  934. cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)")
  935. with self.assertRaises(IntegrityError):
  936. with atomic():
  937. cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)")
  938. cursor.execute("DELETE FROM test_alunto_pony")
  939. # And test reversal
  940. with connection.schema_editor() as editor:
  941. operation.database_backwards("test_alunto", editor, new_state, project_state)
  942. cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)")
  943. cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)")
  944. cursor.execute("DELETE FROM test_alunto_pony")
  945. # Test flat unique_together
  946. operation = migrations.AlterUniqueTogether("Pony", ("pink", "weight"))
  947. operation.state_forwards("test_alunto", new_state)
  948. self.assertEqual(len(new_state.models["test_alunto", "pony"].options.get("unique_together", set())), 1)
  949. def test_alter_unique_together_remove(self):
  950. operation = migrations.AlterUniqueTogether("Pony", None)
  951. self.assertEqual(operation.describe(), "Alter unique_together for Pony (0 constraint(s))")
  952. def test_alter_index_together(self):
  953. """
  954. Tests the AlterIndexTogether operation.
  955. """
  956. project_state = self.set_up_test_model("test_alinto")
  957. # Test the state alteration
  958. operation = migrations.AlterIndexTogether("Pony", [("pink", "weight")])
  959. self.assertEqual(operation.describe(), "Alter index_together for Pony (1 constraint(s))")
  960. new_state = project_state.clone()
  961. operation.state_forwards("test_alinto", new_state)
  962. self.assertEqual(len(project_state.models["test_alinto", "pony"].options.get("index_together", set())), 0)
  963. self.assertEqual(len(new_state.models["test_alinto", "pony"].options.get("index_together", set())), 1)
  964. # Make sure there's no matching index
  965. self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"])
  966. # Test the database alteration
  967. with connection.schema_editor() as editor:
  968. operation.database_forwards("test_alinto", editor, project_state, new_state)
  969. self.assertIndexExists("test_alinto_pony", ["pink", "weight"])
  970. # And test reversal
  971. with connection.schema_editor() as editor:
  972. operation.database_backwards("test_alinto", editor, new_state, project_state)
  973. self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"])
  974. def test_alter_index_together_remove(self):
  975. operation = migrations.AlterIndexTogether("Pony", None)
  976. self.assertEqual(operation.describe(), "Alter index_together for Pony (0 constraint(s))")
  977. def test_alter_model_options(self):
  978. """
  979. Tests the AlterModelOptions operation.
  980. """
  981. project_state = self.set_up_test_model("test_almoop")
  982. # Test the state alteration (no DB alteration to test)
  983. operation = migrations.AlterModelOptions("Pony", {"permissions": [("can_groom", "Can groom")]})
  984. self.assertEqual(operation.describe(), "Change Meta options on Pony")
  985. new_state = project_state.clone()
  986. operation.state_forwards("test_almoop", new_state)
  987. self.assertEqual(len(project_state.models["test_almoop", "pony"].options.get("permissions", [])), 0)
  988. self.assertEqual(len(new_state.models["test_almoop", "pony"].options.get("permissions", [])), 1)
  989. self.assertEqual(new_state.models["test_almoop", "pony"].options["permissions"][0][0], "can_groom")
  990. def test_alter_model_options_emptying(self):
  991. """
  992. Tests that the AlterModelOptions operation removes keys from the dict (#23121)
  993. """
  994. project_state = self.set_up_test_model("test_almoop", options=True)
  995. # Test the state alteration (no DB alteration to test)
  996. operation = migrations.AlterModelOptions("Pony", {})
  997. self.assertEqual(operation.describe(), "Change Meta options on Pony")
  998. new_state = project_state.clone()
  999. operation.state_forwards("test_almoop", new_state)
  1000. self.assertEqual(len(project_state.models["test_almoop", "pony"].options.get("permissions", [])), 1)
  1001. self.assertEqual(len(new_state.models["test_almoop", "pony"].options.get("permissions", [])), 0)
  1002. def test_alter_order_with_respect_to(self):
  1003. """
  1004. Tests the AlterOrderWithRespectTo operation.
  1005. """
  1006. project_state = self.set_up_test_model("test_alorwrtto", related_model=True)
  1007. # Test the state alteration
  1008. operation = migrations.AlterOrderWithRespectTo("Rider", "pony")
  1009. self.assertEqual(operation.describe(), "Set order_with_respect_to on Rider to pony")
  1010. new_state = project_state.clone()
  1011. operation.state_forwards("test_alorwrtto", new_state)
  1012. self.assertEqual(project_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), None)
  1013. self.assertEqual(new_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), "pony")
  1014. # Make sure there's no matching index
  1015. self.assertColumnNotExists("test_alorwrtto_rider", "_order")
  1016. # Test the database alteration
  1017. with connection.schema_editor() as editor:
  1018. operation.database_forwards("test_alorwrtto", editor, project_state, new_state)
  1019. self.assertColumnExists("test_alorwrtto_rider", "_order")
  1020. # And test reversal
  1021. with connection.schema_editor() as editor:
  1022. operation.database_backwards("test_alorwrtto", editor, new_state, project_state)
  1023. self.assertColumnNotExists("test_alorwrtto_rider", "_order")
  1024. def test_alter_fk(self):
  1025. """
  1026. Tests that creating and then altering an FK works correctly
  1027. and deals with the pending SQL (#23091)
  1028. """
  1029. project_state = self.set_up_test_model("test_alfk")
  1030. # Test adding and then altering the FK in one go
  1031. create_operation = migrations.CreateModel(
  1032. name="Rider",
  1033. fields=[
  1034. ("id", models.AutoField(primary_key=True)),
  1035. ("pony", models.ForeignKey(to="Pony")),
  1036. ],
  1037. )
  1038. create_state = project_state.clone()
  1039. create_operation.state_forwards("test_alfk", create_state)
  1040. alter_operation = migrations.AlterField(
  1041. model_name='Rider',
  1042. name='pony',
  1043. field=models.ForeignKey(editable=False, to="Pony"),
  1044. )
  1045. alter_state = create_state.clone()
  1046. alter_operation.state_forwards("test_alfk", alter_state)
  1047. with connection.schema_editor() as editor:
  1048. create_operation.database_forwards("test_alfk", editor, project_state, create_state)
  1049. alter_operation.database_forwards("test_alfk", editor, create_state, alter_state)
  1050. def test_alter_fk_non_fk(self):
  1051. """
  1052. Tests that altering an FK to a non-FK works (#23244)
  1053. """
  1054. # Test the state alteration
  1055. operation = migrations.AlterField(
  1056. model_name="Rider",
  1057. name="pony",
  1058. field=models.FloatField(),
  1059. )
  1060. project_state, new_state = self.make_test_state("test_afknfk", operation, related_model=True)
  1061. # Test the database alteration
  1062. self.assertColumnExists("test_afknfk_rider", "pony_id")
  1063. self.assertColumnNotExists("test_afknfk_rider", "pony")
  1064. with connection.schema_editor() as editor:
  1065. operation.database_forwards("test_afknfk", editor, project_state, new_state)
  1066. self.assertColumnExists("test_afknfk_rider", "pony")
  1067. self.assertColumnNotExists("test_afknfk_rider", "pony_id")
  1068. # And test reversal
  1069. with connection.schema_editor() as editor:
  1070. operation.database_backwards("test_afknfk", editor, new_state, project_state)
  1071. self.assertColumnExists("test_afknfk_rider", "pony_id")
  1072. self.assertColumnNotExists("test_afknfk_rider", "pony")
  1073. @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
  1074. def test_run_sql(self):
  1075. """
  1076. Tests the RunSQL operation.
  1077. """
  1078. project_state = self.set_up_test_model("test_runsql")
  1079. # Create the operation
  1080. operation = migrations.RunSQL(
  1081. # Use a multi-line string with a comment to test splitting on SQLite and MySQL respectively
  1082. "CREATE TABLE i_love_ponies (id int, special_thing varchar(15));\n"
  1083. "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 'i love ponies'); -- this is magic!\n"
  1084. "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 'i love django');\n"
  1085. "UPDATE i_love_ponies SET special_thing = 'Ponies' WHERE special_thing LIKE '%%ponies';"
  1086. "UPDATE i_love_ponies SET special_thing = 'Django' WHERE special_thing LIKE '%django';",
  1087. # Run delete queries to test for parameter substitution failure
  1088. # reported in #23426
  1089. "DELETE FROM i_love_ponies WHERE special_thing LIKE '%Django%';"
  1090. "DELETE FROM i_love_ponies WHERE special_thing LIKE '%%Ponies%%';"
  1091. "DROP TABLE i_love_ponies",
  1092. state_operations=[migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))])],
  1093. )
  1094. self.assertEqual(operation.describe(), "Raw SQL operation")
  1095. # Test the state alteration
  1096. new_state = project_state.clone()
  1097. operation.state_forwards("test_runsql", new_state)
  1098. self.assertEqual(len(new_state.models["test_runsql", "somethingelse"].fields), 1)
  1099. # Make sure there's no table
  1100. self.assertTableNotExists("i_love_ponies")
  1101. # Test the database alteration
  1102. with connection.schema_editor() as editor:
  1103. operation.database_forwards("test_runsql", editor, project_state, new_state)
  1104. self.assertTableExists("i_love_ponies")
  1105. # Make sure all the SQL was processed
  1106. with connection.cursor() as cursor:
  1107. cursor.execute("SELECT COUNT(*) FROM i_love_ponies")
  1108. self.assertEqual(cursor.fetchall()[0][0], 2)
  1109. cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Django'")
  1110. self.assertEqual(cursor.fetchall()[0][0], 1)
  1111. cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Ponies'")
  1112. self.assertEqual(cursor.fetchall()[0][0], 1)
  1113. # And test reversal
  1114. self.assertTrue(operation.reversible)
  1115. with connection.schema_editor() as editor:
  1116. operation.database_backwards("test_runsql", editor, new_state, project_state)
  1117. self.assertTableNotExists("i_love_ponies")
  1118. @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
  1119. def test_run_sql_params(self):
  1120. """
  1121. #23426 - RunSQL should accept parameters.
  1122. """
  1123. project_state = self.set_up_test_model("test_runsql")
  1124. # Create the operation
  1125. operation = migrations.RunSQL(
  1126. "CREATE TABLE i_love_ponies (id int, special_thing varchar(15));",
  1127. "DROP TABLE i_love_ponies",
  1128. )
  1129. param_operation = migrations.RunSQL(
  1130. # forwards
  1131. (
  1132. "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 'Django');",
  1133. ["INSERT INTO i_love_ponies (id, special_thing) VALUES (2, %s);", ['Ponies']],
  1134. ("INSERT INTO i_love_ponies (id, special_thing) VALUES (%s, %s);", (3, 'Python',)),
  1135. ),
  1136. # backwards
  1137. [
  1138. "DELETE FROM i_love_ponies WHERE special_thing = 'Django';",
  1139. ["DELETE FROM i_love_ponies WHERE special_thing = 'Ponies';", None],
  1140. ("DELETE FROM i_love_ponies WHERE id = %s OR special_thing = %s;", [3, 'Python']),
  1141. ]
  1142. )
  1143. # Make sure there's no table
  1144. self.assertTableNotExists("i_love_ponies")
  1145. new_state = project_state.clone()
  1146. # Test the database alteration
  1147. with connection.schema_editor() as editor:
  1148. operation.database_forwards("test_runsql", editor, project_state, new_state)
  1149. # Test parameter passing
  1150. with connection.schema_editor() as editor:
  1151. param_operation.database_forwards("test_runsql", editor, project_state, new_state)
  1152. # Make sure all the SQL was processed
  1153. with connection.cursor() as cursor:
  1154. cursor.execute("SELECT COUNT(*) FROM i_love_ponies")
  1155. self.assertEqual(cursor.fetchall()[0][0], 3)
  1156. with connection.schema_editor() as editor:
  1157. param_operation.database_backwards("test_runsql", editor, new_state, project_state)
  1158. with connection.cursor() as cursor:
  1159. cursor.execute("SELECT COUNT(*) FROM i_love_ponies")
  1160. self.assertEqual(cursor.fetchall()[0][0], 0)
  1161. # And test reversal
  1162. with connection.schema_editor() as editor:
  1163. operation.database_backwards("test_runsql", editor, new_state, project_state)
  1164. self.assertTableNotExists("i_love_ponies")
  1165. def test_run_sql_params_invalid(self):
  1166. """
  1167. #23426 - RunSQL should fail when a list of statements with an incorrect
  1168. number of tuples is given.
  1169. """
  1170. project_state = self.set_up_test_model("test_runsql")
  1171. new_state = project_state.clone()
  1172. operation = migrations.RunSQL(
  1173. # forwards
  1174. [
  1175. ["INSERT INTO foo (bar) VALUES ('buz');"]
  1176. ],
  1177. # backwards
  1178. (
  1179. ("DELETE FROM foo WHERE bar = 'buz';", 'invalid', 'parameter count'),
  1180. ),
  1181. )
  1182. with connection.schema_editor() as editor:
  1183. self.assertRaisesRegexp(ValueError,
  1184. "Expected a 2-tuple but got 1",
  1185. operation.database_forwards,
  1186. "test_runsql", editor, project_state, new_state)
  1187. with connection.schema_editor() as editor:
  1188. self.assertRaisesRegexp(ValueError,
  1189. "Expected a 2-tuple but got 3",
  1190. operation.database_backwards,
  1191. "test_runsql", editor, new_state, project_state)
  1192. def test_run_python(self):
  1193. """
  1194. Tests the RunPython operation
  1195. """
  1196. project_state = self.set_up_test_model("test_runpython", mti_model=True)
  1197. # Create the operation
  1198. def inner_method(models, schema_editor):
  1199. Pony = models.get_model("test_runpython", "Pony")
  1200. Pony.objects.create(pink=1, weight=3.55)
  1201. Pony.objects.create(weight=5)
  1202. def inner_method_reverse(models, schema_editor):
  1203. Pony = models.get_model("test_runpython", "Pony")
  1204. Pony.objects.filter(pink=1, weight=3.55).delete()
  1205. Pony.objects.filter(weight=5).delete()
  1206. operation = migrations.RunPython(inner_method, reverse_code=inner_method_reverse)
  1207. self.assertEqual(operation.describe(), "Raw Python operation")
  1208. # Test the state alteration does nothing
  1209. new_state = project_state.clone()
  1210. operation.state_forwards("test_runpython", new_state)
  1211. self.assertEqual(new_state, project_state)
  1212. # Test the database alteration
  1213. self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 0)
  1214. with connection.schema_editor() as editor:
  1215. operation.database_forwards("test_runpython", editor, project_state, new_state)
  1216. self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 2)
  1217. # Now test reversal
  1218. self.assertTrue(operation.reversible)
  1219. with connection.schema_editor() as editor:
  1220. operation.database_backwards("test_runpython", editor, project_state, new_state)
  1221. self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 0)
  1222. # Now test we can't use a string
  1223. with self.assertRaises(ValueError):
  1224. operation = migrations.RunPython("print 'ahahaha'")
  1225. # Also test reversal fails, with an operation identical to above but without reverse_code set
  1226. no_reverse_operation = migrations.RunPython(inner_method)
  1227. self.assertFalse(no_reverse_operation.reversible)
  1228. with connection.schema_editor() as editor:
  1229. no_reverse_operation.database_forwards("test_runpython", editor, project_state, new_state)
  1230. with self.assertRaises(NotImplementedError):
  1231. no_reverse_operation.database_backwards("test_runpython", editor, new_state, project_state)
  1232. self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 2)
  1233. def create_ponies(models, schema_editor):
  1234. Pony = models.get_model("test_runpython", "Pony")
  1235. pony1 = Pony.objects.create(pink=1, weight=3.55)
  1236. self.assertIsNot(pony1.pk, None)
  1237. pony2 = Pony.objects.create(weight=5)
  1238. self.assertIsNot(pony2.pk, None)
  1239. self.assertNotEqual(pony1.pk, pony2.pk)
  1240. operation = migrations.RunPython(create_ponies)
  1241. with connection.schema_editor() as editor:
  1242. operation.database_forwards("test_runpython", editor, project_state, new_state)
  1243. self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 4)
  1244. def create_shetlandponies(models, schema_editor):
  1245. ShetlandPony = models.get_model("test_runpython", "ShetlandPony")
  1246. pony1 = ShetlandPony.objects.create(weight=4.0)
  1247. self.assertIsNot(pony1.pk, None)
  1248. pony2 = ShetlandPony.objects.create(weight=5.0)
  1249. self.assertIsNot(pony2.pk, None)
  1250. self.assertNotEqual(pony1.pk, pony2.pk)
  1251. operation = migrations.RunPython(create_shetlandponies)
  1252. with connection.schema_editor() as editor:
  1253. operation.database_forwards("test_runpython", editor, project_state, new_state)
  1254. self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 6)
  1255. self.assertEqual(project_state.render().get_model("test_runpython", "ShetlandPony").objects.count(), 2)
  1256. def test_run_python_atomic(self):
  1257. """
  1258. Tests the RunPython operation correctly handles the "atomic" keyword
  1259. """
  1260. project_state = self.set_up_test_model("test_runpythonatomic", mti_model=True)
  1261. def inner_method(models, schema_editor):
  1262. Pony = models.get_model("test_runpythonatomic", "Pony")
  1263. Pony.objects.create(pink=1, weight=3.55)
  1264. raise ValueError("Adrian hates ponies.")
  1265. atomic_migration = Migration("test", "test_runpythonatomic")
  1266. atomic_migration.operations = [migrations.RunPython(inner_method)]
  1267. non_atomic_migration = Migration("test", "test_runpythonatomic")
  1268. non_atomic_migration.operations = [migrations.RunPython(inner_method, atomic=False)]
  1269. # If we're a fully-transactional database, both versions should rollback
  1270. if connection.features.can_rollback_ddl:
  1271. self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
  1272. with self.assertRaises(ValueError):
  1273. with connection.schema_editor() as editor:
  1274. atomic_migration.apply(project_state, editor)
  1275. self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
  1276. with self.assertRaises(ValueError):
  1277. with connection.schema_editor() as editor:
  1278. non_atomic_migration.apply(project_state, editor)
  1279. self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
  1280. # Otherwise, the non-atomic operation should leave a row there
  1281. else:
  1282. self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
  1283. with self.assertRaises(ValueError):
  1284. with connection.schema_editor() as editor:
  1285. atomic_migration.apply(project_state, editor)
  1286. self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
  1287. with self.assertRaises(ValueError):
  1288. with connection.schema_editor() as editor:
  1289. non_atomic_migration.apply(project_state, editor)
  1290. self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 1)
  1291. @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
  1292. def test_separate_database_and_state(self):
  1293. """
  1294. Tests the SeparateDatabaseAndState operation.
  1295. """
  1296. project_state = self.set_up_test_model("test_separatedatabaseandstate")
  1297. # Create the operation
  1298. database_operation = migrations.RunSQL(
  1299. "CREATE TABLE i_love_ponies (id int, special_thing int);",
  1300. "DROP TABLE i_love_ponies;"
  1301. )
  1302. state_operation = migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))])
  1303. operation = migrations.SeparateDatabaseAndState(
  1304. state_operations=[state_operation],
  1305. database_operations=[database_operation]
  1306. )
  1307. self.assertEqual(operation.describe(), "Custom state/database change combination")
  1308. # Test the state alteration
  1309. new_state = project_state.clone()
  1310. operation.state_forwards("test_separatedatabaseandstate", new_state)
  1311. self.assertEqual(len(new_state.models["test_separatedatabaseandstate", "somethingelse"].fields), 1)
  1312. # Make sure there's no table
  1313. self.assertTableNotExists("i_love_ponies")
  1314. # Test the database alteration
  1315. with connection.schema_editor() as editor:
  1316. operation.database_forwards("test_separatedatabaseandstate", editor, project_state, new_state)
  1317. self.assertTableExists("i_love_ponies")
  1318. # And test reversal
  1319. self.assertTrue(operation.reversible)
  1320. with connection.schema_editor() as editor:
  1321. operation.database_backwards("test_separatedatabaseandstate", editor, new_state, project_state)
  1322. self.assertTableNotExists("i_love_ponies")
  1323. class MigrateNothingRouter(object):
  1324. """
  1325. A router that sends all writes to the other database.
  1326. """
  1327. def allow_migrate(self, db, model):
  1328. return False
  1329. class MultiDBOperationTests(MigrationTestBase):
  1330. multi_db = True
  1331. def setUp(self):
  1332. # Make the 'other' database appear to be a replica of the 'default'
  1333. self.old_routers = router.routers
  1334. router.routers = [MigrateNothingRouter()]
  1335. def tearDown(self):
  1336. # Restore the 'other' database as an independent database
  1337. router.routers = self.old_routers
  1338. def test_create_model(self):
  1339. """
  1340. Tests that CreateModel honours multi-db settings.
  1341. """
  1342. operation = migrations.CreateModel(
  1343. "Pony",
  1344. [
  1345. ("id", models.AutoField(primary_key=True)),
  1346. ("pink", models.IntegerField(default=1)),
  1347. ],
  1348. )
  1349. # Test the state alteration
  1350. project_state = ProjectState()
  1351. new_state = project_state.clone()
  1352. operation.state_forwards("test_crmo", new_state)
  1353. # Test the database alteration
  1354. self.assertTableNotExists("test_crmo_pony")
  1355. with connection.schema_editor() as editor:
  1356. operation.database_forwards("test_crmo", editor, project_state, new_state)
  1357. self.assertTableNotExists("test_crmo_pony")
  1358. # And test reversal
  1359. with connection.schema_editor() as editor:
  1360. operation.database_backwards("test_crmo", editor, new_state, project_state)
  1361. self.assertTableNotExists("test_crmo_pony")
  1362. class SwappableOperationTests(OperationTestBase):
  1363. """
  1364. Tests that key operations ignore swappable models
  1365. (we don't want to replicate all of them here, as the functionality
  1366. is in a common base class anyway)
  1367. """
  1368. available_apps = [
  1369. "migrations",
  1370. "django.contrib.auth",
  1371. ]
  1372. @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel")
  1373. def test_create_ignore_swapped(self):
  1374. """
  1375. Tests that the CreateTable operation ignores swapped models.
  1376. """
  1377. operation = migrations.CreateModel(
  1378. "Pony",
  1379. [
  1380. ("id", models.AutoField(primary_key=True)),
  1381. ("pink", models.IntegerField(default=1)),
  1382. ],
  1383. options={
  1384. "swappable": "TEST_SWAP_MODEL",
  1385. },
  1386. )
  1387. # Test the state alteration (it should still be there!)
  1388. project_state = ProjectState()
  1389. new_state = project_state.clone()
  1390. operation.state_forwards("test_crigsw", new_state)
  1391. self.assertEqual(new_state.models["test_crigsw", "pony"].name, "Pony")
  1392. self.assertEqual(len(new_state.models["test_crigsw", "pony"].fields), 2)
  1393. # Test the database alteration
  1394. self.assertTableNotExists("test_crigsw_pony")
  1395. with connection.schema_editor() as editor:
  1396. operation.database_forwards("test_crigsw", editor, project_state, new_state)
  1397. self.assertTableNotExists("test_crigsw_pony")
  1398. # And test reversal
  1399. with connection.schema_editor() as editor:
  1400. operation.database_backwards("test_crigsw", editor, new_state, project_state)
  1401. self.assertTableNotExists("test_crigsw_pony")
  1402. @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel")
  1403. def test_delete_ignore_swapped(self):
  1404. """
  1405. Tests the DeleteModel operation ignores swapped models.
  1406. """
  1407. operation = migrations.DeleteModel("Pony")
  1408. project_state, new_state = self.make_test_state("test_dligsw", operation)
  1409. # Test the database alteration
  1410. self.assertTableNotExists("test_dligsw_pony")
  1411. with connection.schema_editor() as editor:
  1412. operation.database_forwards("test_dligsw", editor, project_state, new_state)
  1413. self.assertTableNotExists("test_dligsw_pony")
  1414. # And test reversal
  1415. with connection.schema_editor() as editor:
  1416. operation.database_backwards("test_dligsw", editor, new_state, project_state)
  1417. self.assertTableNotExists("test_dligsw_pony")
  1418. @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel")
  1419. def test_add_field_ignore_swapped(self):
  1420. """
  1421. Tests the AddField operation.
  1422. """
  1423. # Test the state alteration
  1424. operation = migrations.AddField(
  1425. "Pony",
  1426. "height",
  1427. models.FloatField(null=True, default=5),
  1428. )
  1429. project_state, new_state = self.make_test_state("test_adfligsw", operation)
  1430. # Test the database alteration
  1431. self.assertTableNotExists("test_adfligsw_pony")
  1432. with connection.schema_editor() as editor:
  1433. operation.database_forwards("test_adfligsw", editor, project_state, new_state)
  1434. self.assertTableNotExists("test_adfligsw_pony")
  1435. # And test reversal
  1436. with connection.schema_editor() as editor:
  1437. operation.database_backwards("test_adfligsw", editor, new_state, project_state)
  1438. self.assertTableNotExists("test_adfligsw_pony")