test_autodetector.py 107 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066
  1. # -*- coding: utf-8 -*-
  2. from django.conf import settings
  3. from django.contrib.auth.models import AbstractBaseUser
  4. from django.db import connection, models
  5. from django.db.migrations.autodetector import MigrationAutodetector
  6. from django.db.migrations.graph import MigrationGraph
  7. from django.db.migrations.loader import MigrationLoader
  8. from django.db.migrations.questioner import MigrationQuestioner
  9. from django.db.migrations.state import ModelState, ProjectState
  10. from django.test import TestCase, mock, override_settings
  11. from .models import FoodManager, FoodQuerySet
  12. class DeconstructableObject(object):
  13. """
  14. A custom deconstructable object.
  15. """
  16. def __init__(self, *args, **kwargs):
  17. self.args = args
  18. self.kwargs = kwargs
  19. def deconstruct(self):
  20. return (
  21. self.__module__ + '.' + self.__class__.__name__,
  22. self.args,
  23. self.kwargs
  24. )
  25. class AutodetectorTests(TestCase):
  26. """
  27. Tests the migration autodetector.
  28. """
  29. author_empty = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True))])
  30. author_name = ModelState("testapp", "Author", [
  31. ("id", models.AutoField(primary_key=True)),
  32. ("name", models.CharField(max_length=200)),
  33. ])
  34. author_name_null = ModelState("testapp", "Author", [
  35. ("id", models.AutoField(primary_key=True)),
  36. ("name", models.CharField(max_length=200, null=True)),
  37. ])
  38. author_name_longer = ModelState("testapp", "Author", [
  39. ("id", models.AutoField(primary_key=True)),
  40. ("name", models.CharField(max_length=400)),
  41. ])
  42. author_name_renamed = ModelState("testapp", "Author", [
  43. ("id", models.AutoField(primary_key=True)),
  44. ("names", models.CharField(max_length=200)),
  45. ])
  46. author_name_default = ModelState("testapp", "Author", [
  47. ("id", models.AutoField(primary_key=True)),
  48. ("name", models.CharField(max_length=200, default='Ada Lovelace')),
  49. ])
  50. author_name_deconstructable_1 = ModelState("testapp", "Author", [
  51. ("id", models.AutoField(primary_key=True)),
  52. ("name", models.CharField(max_length=200, default=DeconstructableObject())),
  53. ])
  54. author_name_deconstructable_2 = ModelState("testapp", "Author", [
  55. ("id", models.AutoField(primary_key=True)),
  56. ("name", models.CharField(max_length=200, default=DeconstructableObject())),
  57. ])
  58. author_name_deconstructable_3 = ModelState("testapp", "Author", [
  59. ("id", models.AutoField(primary_key=True)),
  60. ("name", models.CharField(max_length=200, default=models.IntegerField())),
  61. ])
  62. author_name_deconstructable_4 = ModelState("testapp", "Author", [
  63. ("id", models.AutoField(primary_key=True)),
  64. ("name", models.CharField(max_length=200, default=models.IntegerField())),
  65. ])
  66. author_name_deconstructable_list_1 = ModelState("testapp", "Author", [
  67. ("id", models.AutoField(primary_key=True)),
  68. ("name", models.CharField(max_length=200, default=[DeconstructableObject(), 123])),
  69. ])
  70. author_name_deconstructable_list_2 = ModelState("testapp", "Author", [
  71. ("id", models.AutoField(primary_key=True)),
  72. ("name", models.CharField(max_length=200, default=[DeconstructableObject(), 123])),
  73. ])
  74. author_name_deconstructable_list_3 = ModelState("testapp", "Author", [
  75. ("id", models.AutoField(primary_key=True)),
  76. ("name", models.CharField(max_length=200, default=[DeconstructableObject(), 999])),
  77. ])
  78. author_name_deconstructable_tuple_1 = ModelState("testapp", "Author", [
  79. ("id", models.AutoField(primary_key=True)),
  80. ("name", models.CharField(max_length=200, default=(DeconstructableObject(), 123))),
  81. ])
  82. author_name_deconstructable_tuple_2 = ModelState("testapp", "Author", [
  83. ("id", models.AutoField(primary_key=True)),
  84. ("name", models.CharField(max_length=200, default=(DeconstructableObject(), 123))),
  85. ])
  86. author_name_deconstructable_tuple_3 = ModelState("testapp", "Author", [
  87. ("id", models.AutoField(primary_key=True)),
  88. ("name", models.CharField(max_length=200, default=(DeconstructableObject(), 999))),
  89. ])
  90. author_name_deconstructable_dict_1 = ModelState("testapp", "Author", [
  91. ("id", models.AutoField(primary_key=True)),
  92. ("name", models.CharField(max_length=200, default={
  93. 'item': DeconstructableObject(), 'otheritem': 123
  94. })),
  95. ])
  96. author_name_deconstructable_dict_2 = ModelState("testapp", "Author", [
  97. ("id", models.AutoField(primary_key=True)),
  98. ("name", models.CharField(max_length=200, default={
  99. 'item': DeconstructableObject(), 'otheritem': 123
  100. })),
  101. ])
  102. author_name_deconstructable_dict_3 = ModelState("testapp", "Author", [
  103. ("id", models.AutoField(primary_key=True)),
  104. ("name", models.CharField(max_length=200, default={
  105. 'item': DeconstructableObject(), 'otheritem': 999
  106. })),
  107. ])
  108. author_name_nested_deconstructable_1 = ModelState("testapp", "Author", [
  109. ("id", models.AutoField(primary_key=True)),
  110. ("name", models.CharField(max_length=200, default=DeconstructableObject(
  111. DeconstructableObject(1),
  112. (DeconstructableObject('t1'), DeconstructableObject('t2'),),
  113. a=DeconstructableObject('A'),
  114. b=DeconstructableObject(B=DeconstructableObject('c')),
  115. ))),
  116. ])
  117. author_name_nested_deconstructable_2 = ModelState("testapp", "Author", [
  118. ("id", models.AutoField(primary_key=True)),
  119. ("name", models.CharField(max_length=200, default=DeconstructableObject(
  120. DeconstructableObject(1),
  121. (DeconstructableObject('t1'), DeconstructableObject('t2'),),
  122. a=DeconstructableObject('A'),
  123. b=DeconstructableObject(B=DeconstructableObject('c')),
  124. ))),
  125. ])
  126. author_name_nested_deconstructable_changed_arg = ModelState("testapp", "Author", [
  127. ("id", models.AutoField(primary_key=True)),
  128. ("name", models.CharField(max_length=200, default=DeconstructableObject(
  129. DeconstructableObject(1),
  130. (DeconstructableObject('t1'), DeconstructableObject('t2-changed'),),
  131. a=DeconstructableObject('A'),
  132. b=DeconstructableObject(B=DeconstructableObject('c')),
  133. ))),
  134. ])
  135. author_name_nested_deconstructable_extra_arg = ModelState("testapp", "Author", [
  136. ("id", models.AutoField(primary_key=True)),
  137. ("name", models.CharField(max_length=200, default=DeconstructableObject(
  138. DeconstructableObject(1),
  139. (DeconstructableObject('t1'), DeconstructableObject('t2'),),
  140. None,
  141. a=DeconstructableObject('A'),
  142. b=DeconstructableObject(B=DeconstructableObject('c')),
  143. ))),
  144. ])
  145. author_name_nested_deconstructable_changed_kwarg = ModelState("testapp", "Author", [
  146. ("id", models.AutoField(primary_key=True)),
  147. ("name", models.CharField(max_length=200, default=DeconstructableObject(
  148. DeconstructableObject(1),
  149. (DeconstructableObject('t1'), DeconstructableObject('t2'),),
  150. a=DeconstructableObject('A'),
  151. b=DeconstructableObject(B=DeconstructableObject('c-changed')),
  152. ))),
  153. ])
  154. author_name_nested_deconstructable_extra_kwarg = ModelState("testapp", "Author", [
  155. ("id", models.AutoField(primary_key=True)),
  156. ("name", models.CharField(max_length=200, default=DeconstructableObject(
  157. DeconstructableObject(1),
  158. (DeconstructableObject('t1'), DeconstructableObject('t2'),),
  159. a=DeconstructableObject('A'),
  160. b=DeconstructableObject(B=DeconstructableObject('c')),
  161. c=None,
  162. ))),
  163. ])
  164. author_custom_pk = ModelState("testapp", "Author", [("pk_field", models.IntegerField(primary_key=True))])
  165. author_with_biography_non_blank = ModelState("testapp", "Author", [
  166. ("id", models.AutoField(primary_key=True)),
  167. ("name", models.CharField()),
  168. ("biography", models.TextField()),
  169. ])
  170. author_with_biography_blank = ModelState("testapp", "Author", [
  171. ("id", models.AutoField(primary_key=True)),
  172. ("name", models.CharField(blank=True)),
  173. ("biography", models.TextField(blank=True)),
  174. ])
  175. author_with_book = ModelState("testapp", "Author", [
  176. ("id", models.AutoField(primary_key=True)),
  177. ("name", models.CharField(max_length=200)),
  178. ("book", models.ForeignKey("otherapp.Book")),
  179. ])
  180. author_with_book_order_wrt = ModelState("testapp", "Author", [
  181. ("id", models.AutoField(primary_key=True)),
  182. ("name", models.CharField(max_length=200)),
  183. ("book", models.ForeignKey("otherapp.Book")),
  184. ], options={"order_with_respect_to": "book"})
  185. author_renamed_with_book = ModelState("testapp", "Writer", [
  186. ("id", models.AutoField(primary_key=True)),
  187. ("name", models.CharField(max_length=200)),
  188. ("book", models.ForeignKey("otherapp.Book")),
  189. ])
  190. author_with_publisher_string = ModelState("testapp", "Author", [
  191. ("id", models.AutoField(primary_key=True)),
  192. ("name", models.CharField(max_length=200)),
  193. ("publisher_name", models.CharField(max_length=200)),
  194. ])
  195. author_with_publisher = ModelState("testapp", "Author", [
  196. ("id", models.AutoField(primary_key=True)),
  197. ("name", models.CharField(max_length=200)),
  198. ("publisher", models.ForeignKey("testapp.Publisher")),
  199. ])
  200. author_with_user = ModelState("testapp", "Author", [
  201. ("id", models.AutoField(primary_key=True)),
  202. ("name", models.CharField(max_length=200)),
  203. ("user", models.ForeignKey("auth.User")),
  204. ])
  205. author_with_custom_user = ModelState("testapp", "Author", [
  206. ("id", models.AutoField(primary_key=True)),
  207. ("name", models.CharField(max_length=200)),
  208. ("user", models.ForeignKey("thirdapp.CustomUser")),
  209. ])
  210. author_proxy = ModelState("testapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author",))
  211. author_proxy_options = ModelState("testapp", "AuthorProxy", [], {
  212. "proxy": True,
  213. "verbose_name": "Super Author",
  214. }, ("testapp.author", ))
  215. author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author", ))
  216. author_proxy_third = ModelState("thirdapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author", ))
  217. author_proxy_proxy = ModelState("testapp", "AAuthorProxyProxy", [], {"proxy": True}, ("testapp.authorproxy", ))
  218. author_unmanaged = ModelState("testapp", "AuthorUnmanaged", [], {"managed": False}, ("testapp.author", ))
  219. author_unmanaged_managed = ModelState("testapp", "AuthorUnmanaged", [], {}, ("testapp.author", ))
  220. author_unmanaged_default_pk = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True))])
  221. author_unmanaged_custom_pk = ModelState("testapp", "Author", [
  222. ("pk_field", models.IntegerField(primary_key=True)),
  223. ])
  224. author_with_m2m = ModelState("testapp", "Author", [
  225. ("id", models.AutoField(primary_key=True)),
  226. ("publishers", models.ManyToManyField("testapp.Publisher")),
  227. ])
  228. author_with_m2m_blank = ModelState("testapp", "Author", [
  229. ("id", models.AutoField(primary_key=True)),
  230. ("publishers", models.ManyToManyField("testapp.Publisher", blank=True)),
  231. ])
  232. author_with_m2m_through = ModelState("testapp", "Author", [
  233. ("id", models.AutoField(primary_key=True)),
  234. ("publishers", models.ManyToManyField("testapp.Publisher", through="testapp.Contract")),
  235. ])
  236. author_with_former_m2m = ModelState("testapp", "Author", [
  237. ("id", models.AutoField(primary_key=True)),
  238. ("publishers", models.CharField(max_length=100)),
  239. ])
  240. author_with_options = ModelState("testapp", "Author", [
  241. ("id", models.AutoField(primary_key=True)),
  242. ], {
  243. "permissions": [('can_hire', 'Can hire')],
  244. "verbose_name": "Authi",
  245. })
  246. author_with_db_table_options = ModelState("testapp", "Author", [
  247. ("id", models.AutoField(primary_key=True)),
  248. ], {"db_table": "author_one"})
  249. author_with_new_db_table_options = ModelState("testapp", "Author", [
  250. ("id", models.AutoField(primary_key=True)),
  251. ], {"db_table": "author_two"})
  252. author_renamed_with_db_table_options = ModelState("testapp", "NewAuthor", [
  253. ("id", models.AutoField(primary_key=True)),
  254. ], {"db_table": "author_one"})
  255. author_renamed_with_new_db_table_options = ModelState("testapp", "NewAuthor", [
  256. ("id", models.AutoField(primary_key=True)),
  257. ], {"db_table": "author_three"})
  258. contract = ModelState("testapp", "Contract", [
  259. ("id", models.AutoField(primary_key=True)),
  260. ("author", models.ForeignKey("testapp.Author")),
  261. ("publisher", models.ForeignKey("testapp.Publisher")),
  262. ])
  263. publisher = ModelState("testapp", "Publisher", [
  264. ("id", models.AutoField(primary_key=True)),
  265. ("name", models.CharField(max_length=100)),
  266. ])
  267. publisher_with_author = ModelState("testapp", "Publisher", [
  268. ("id", models.AutoField(primary_key=True)),
  269. ("author", models.ForeignKey("testapp.Author")),
  270. ("name", models.CharField(max_length=100)),
  271. ])
  272. publisher_with_aardvark_author = ModelState("testapp", "Publisher", [
  273. ("id", models.AutoField(primary_key=True)),
  274. ("author", models.ForeignKey("testapp.Aardvark")),
  275. ("name", models.CharField(max_length=100)),
  276. ])
  277. publisher_with_book = ModelState("testapp", "Publisher", [
  278. ("id", models.AutoField(primary_key=True)),
  279. ("author", models.ForeignKey("otherapp.Book")),
  280. ("name", models.CharField(max_length=100)),
  281. ])
  282. other_pony = ModelState("otherapp", "Pony", [
  283. ("id", models.AutoField(primary_key=True)),
  284. ])
  285. other_pony_food = ModelState("otherapp", "Pony", [
  286. ("id", models.AutoField(primary_key=True)),
  287. ], managers=[
  288. ('food_qs', FoodQuerySet.as_manager()),
  289. ('food_mgr', FoodManager('a', 'b')),
  290. ('food_mgr_kwargs', FoodManager('x', 'y', 3, 4)),
  291. ])
  292. other_stable = ModelState("otherapp", "Stable", [("id", models.AutoField(primary_key=True))])
  293. third_thing = ModelState("thirdapp", "Thing", [("id", models.AutoField(primary_key=True))])
  294. book = ModelState("otherapp", "Book", [
  295. ("id", models.AutoField(primary_key=True)),
  296. ("author", models.ForeignKey("testapp.Author")),
  297. ("title", models.CharField(max_length=200)),
  298. ])
  299. book_proxy_fk = ModelState("otherapp", "Book", [
  300. ("id", models.AutoField(primary_key=True)),
  301. ("author", models.ForeignKey("thirdapp.AuthorProxy")),
  302. ("title", models.CharField(max_length=200)),
  303. ])
  304. book_migrations_fk = ModelState("otherapp", "Book", [
  305. ("id", models.AutoField(primary_key=True)),
  306. ("author", models.ForeignKey("migrations.UnmigratedModel")),
  307. ("title", models.CharField(max_length=200)),
  308. ])
  309. book_with_no_author = ModelState("otherapp", "Book", [
  310. ("id", models.AutoField(primary_key=True)),
  311. ("title", models.CharField(max_length=200)),
  312. ])
  313. book_with_author_renamed = ModelState("otherapp", "Book", [
  314. ("id", models.AutoField(primary_key=True)),
  315. ("author", models.ForeignKey("testapp.Writer")),
  316. ("title", models.CharField(max_length=200)),
  317. ])
  318. book_with_field_and_author_renamed = ModelState("otherapp", "Book", [
  319. ("id", models.AutoField(primary_key=True)),
  320. ("writer", models.ForeignKey("testapp.Writer")),
  321. ("title", models.CharField(max_length=200)),
  322. ])
  323. book_with_multiple_authors = ModelState("otherapp", "Book", [
  324. ("id", models.AutoField(primary_key=True)),
  325. ("authors", models.ManyToManyField("testapp.Author")),
  326. ("title", models.CharField(max_length=200)),
  327. ])
  328. book_with_multiple_authors_through_attribution = ModelState("otherapp", "Book", [
  329. ("id", models.AutoField(primary_key=True)),
  330. ("authors", models.ManyToManyField("testapp.Author", through="otherapp.Attribution")),
  331. ("title", models.CharField(max_length=200)),
  332. ])
  333. book_foo_together = ModelState("otherapp", "Book", [
  334. ("id", models.AutoField(primary_key=True)),
  335. ("author", models.ForeignKey("testapp.Author")),
  336. ("title", models.CharField(max_length=200)),
  337. ], {
  338. "index_together": {("author", "title")},
  339. "unique_together": {("author", "title")},
  340. })
  341. book_foo_together_2 = ModelState("otherapp", "Book", [
  342. ("id", models.AutoField(primary_key=True)),
  343. ("author", models.ForeignKey("testapp.Author")),
  344. ("title", models.CharField(max_length=200)),
  345. ], {
  346. "index_together": {("title", "author")},
  347. "unique_together": {("title", "author")},
  348. })
  349. book_foo_together_3 = ModelState("otherapp", "Book", [
  350. ("id", models.AutoField(primary_key=True)),
  351. ("newfield", models.IntegerField()),
  352. ("author", models.ForeignKey("testapp.Author")),
  353. ("title", models.CharField(max_length=200)),
  354. ], {
  355. "index_together": {("title", "newfield")},
  356. "unique_together": {("title", "newfield")},
  357. })
  358. book_foo_together_4 = ModelState("otherapp", "Book", [
  359. ("id", models.AutoField(primary_key=True)),
  360. ("newfield2", models.IntegerField()),
  361. ("author", models.ForeignKey("testapp.Author")),
  362. ("title", models.CharField(max_length=200)),
  363. ], {
  364. "index_together": {("title", "newfield2")},
  365. "unique_together": {("title", "newfield2")},
  366. })
  367. attribution = ModelState("otherapp", "Attribution", [
  368. ("id", models.AutoField(primary_key=True)),
  369. ("author", models.ForeignKey("testapp.Author")),
  370. ("book", models.ForeignKey("otherapp.Book")),
  371. ])
  372. edition = ModelState("thirdapp", "Edition", [
  373. ("id", models.AutoField(primary_key=True)),
  374. ("book", models.ForeignKey("otherapp.Book")),
  375. ])
  376. custom_user = ModelState("thirdapp", "CustomUser", [
  377. ("id", models.AutoField(primary_key=True)),
  378. ("username", models.CharField(max_length=255)),
  379. ], bases=(AbstractBaseUser, ))
  380. custom_user_no_inherit = ModelState("thirdapp", "CustomUser", [
  381. ("id", models.AutoField(primary_key=True)),
  382. ("username", models.CharField(max_length=255)),
  383. ])
  384. aardvark = ModelState("thirdapp", "Aardvark", [("id", models.AutoField(primary_key=True))])
  385. aardvark_testapp = ModelState("testapp", "Aardvark", [("id", models.AutoField(primary_key=True))])
  386. aardvark_based_on_author = ModelState("testapp", "Aardvark", [], bases=("testapp.Author", ))
  387. aardvark_pk_fk_author = ModelState("testapp", "Aardvark", [
  388. ("id", models.OneToOneField("testapp.Author", primary_key=True)),
  389. ])
  390. knight = ModelState("eggs", "Knight", [("id", models.AutoField(primary_key=True))])
  391. rabbit = ModelState("eggs", "Rabbit", [
  392. ("id", models.AutoField(primary_key=True)),
  393. ("knight", models.ForeignKey("eggs.Knight")),
  394. ("parent", models.ForeignKey("eggs.Rabbit")),
  395. ], {"unique_together": {("parent", "knight")}})
  396. def repr_changes(self, changes, include_dependencies=False):
  397. output = ""
  398. for app_label, migrations in sorted(changes.items()):
  399. output += " %s:\n" % app_label
  400. for migration in migrations:
  401. output += " %s\n" % migration.name
  402. for operation in migration.operations:
  403. output += " %s\n" % operation
  404. if include_dependencies:
  405. output += " Dependencies:\n"
  406. if migration.dependencies:
  407. for dep in migration.dependencies:
  408. output += " %s\n" % (dep,)
  409. else:
  410. output += " None\n"
  411. return output
  412. def assertNumberMigrations(self, changes, app_label, number):
  413. if len(changes.get(app_label, [])) != number:
  414. self.fail("Incorrect number of migrations (%s) for %s (expected %s)\n%s" % (
  415. len(changes.get(app_label, [])),
  416. app_label,
  417. number,
  418. self.repr_changes(changes),
  419. ))
  420. def assertMigrationDependencies(self, changes, app_label, index, dependencies):
  421. if not changes.get(app_label):
  422. self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes)))
  423. if len(changes[app_label]) < index + 1:
  424. self.fail("No migration at index %s for %s\n%s" % (index, app_label, self.repr_changes(changes)))
  425. migration = changes[app_label][index]
  426. if set(migration.dependencies) != set(dependencies):
  427. self.fail("Migration dependencies mismatch for %s.%s (expected %s):\n%s" % (
  428. app_label,
  429. migration.name,
  430. dependencies,
  431. self.repr_changes(changes, include_dependencies=True),
  432. ))
  433. def assertOperationTypes(self, changes, app_label, index, types):
  434. if not changes.get(app_label):
  435. self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes)))
  436. if len(changes[app_label]) < index + 1:
  437. self.fail("No migration at index %s for %s\n%s" % (index, app_label, self.repr_changes(changes)))
  438. migration = changes[app_label][index]
  439. real_types = [operation.__class__.__name__ for operation in migration.operations]
  440. if types != real_types:
  441. self.fail("Operation type mismatch for %s.%s (expected %s):\n%s" % (
  442. app_label,
  443. migration.name,
  444. types,
  445. self.repr_changes(changes),
  446. ))
  447. def assertOperationAttributes(self, changes, app_label, index, operation_index, **attrs):
  448. if not changes.get(app_label):
  449. self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes)))
  450. if len(changes[app_label]) < index + 1:
  451. self.fail("No migration at index %s for %s\n%s" % (index, app_label, self.repr_changes(changes)))
  452. migration = changes[app_label][index]
  453. if len(changes[app_label]) < index + 1:
  454. self.fail("No operation at index %s for %s.%s\n%s" % (
  455. operation_index,
  456. app_label,
  457. migration.name,
  458. self.repr_changes(changes),
  459. ))
  460. operation = migration.operations[operation_index]
  461. for attr, value in attrs.items():
  462. if getattr(operation, attr, None) != value:
  463. self.fail("Attribute mismatch for %s.%s op #%s, %s (expected %r, got %r):\n%s" % (
  464. app_label,
  465. migration.name,
  466. operation_index,
  467. attr,
  468. value,
  469. getattr(operation, attr, None),
  470. self.repr_changes(changes),
  471. ))
  472. def assertOperationFieldAttributes(self, changes, app_label, index, operation_index, **attrs):
  473. if not changes.get(app_label):
  474. self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes)))
  475. if len(changes[app_label]) < index + 1:
  476. self.fail("No migration at index %s for %s\n%s" % (index, app_label, self.repr_changes(changes)))
  477. migration = changes[app_label][index]
  478. if len(changes[app_label]) < index + 1:
  479. self.fail("No operation at index %s for %s.%s\n%s" % (
  480. operation_index,
  481. app_label,
  482. migration.name,
  483. self.repr_changes(changes),
  484. ))
  485. operation = migration.operations[operation_index]
  486. if not hasattr(operation, 'field'):
  487. self.fail("No field attribute for %s.%s op #%s." % (
  488. app_label,
  489. migration.name,
  490. operation_index,
  491. ))
  492. field = operation.field
  493. for attr, value in attrs.items():
  494. if getattr(field, attr, None) != value:
  495. self.fail("Field attribute mismatch for %s.%s op #%s, field.%s (expected %r, got %r):\n%s" % (
  496. app_label,
  497. migration.name,
  498. operation_index,
  499. attr,
  500. value,
  501. getattr(field, attr, None),
  502. self.repr_changes(changes),
  503. ))
  504. def make_project_state(self, model_states):
  505. "Shortcut to make ProjectStates from lists of predefined models"
  506. project_state = ProjectState()
  507. for model_state in model_states:
  508. project_state.add_model(model_state.clone())
  509. return project_state
  510. def test_arrange_for_graph(self):
  511. """Tests auto-naming of migrations for graph matching."""
  512. # Make a fake graph
  513. graph = MigrationGraph()
  514. graph.add_node(("testapp", "0001_initial"), None)
  515. graph.add_node(("testapp", "0002_foobar"), None)
  516. graph.add_node(("otherapp", "0001_initial"), None)
  517. graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("testapp", "0001_initial"))
  518. graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("otherapp", "0001_initial"))
  519. # Use project state to make a new migration change set
  520. before = self.make_project_state([])
  521. after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable])
  522. autodetector = MigrationAutodetector(before, after)
  523. changes = autodetector._detect_changes()
  524. # Run through arrange_for_graph
  525. changes = autodetector.arrange_for_graph(changes, graph)
  526. # Make sure there's a new name, deps match, etc.
  527. self.assertEqual(changes["testapp"][0].name, "0003_author")
  528. self.assertEqual(changes["testapp"][0].dependencies, [("testapp", "0002_foobar")])
  529. self.assertEqual(changes["otherapp"][0].name, "0002_pony_stable")
  530. self.assertEqual(changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")])
  531. def test_trim_apps(self):
  532. """
  533. Tests that trim does not remove dependencies but does remove unwanted
  534. apps.
  535. """
  536. # Use project state to make a new migration change set
  537. before = self.make_project_state([])
  538. after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable, self.third_thing])
  539. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_initial": True}))
  540. changes = autodetector._detect_changes()
  541. # Run through arrange_for_graph
  542. graph = MigrationGraph()
  543. changes = autodetector.arrange_for_graph(changes, graph)
  544. changes["testapp"][0].dependencies.append(("otherapp", "0001_initial"))
  545. changes = autodetector._trim_to_apps(changes, {"testapp"})
  546. # Make sure there's the right set of migrations
  547. self.assertEqual(changes["testapp"][0].name, "0001_initial")
  548. self.assertEqual(changes["otherapp"][0].name, "0001_initial")
  549. self.assertNotIn("thirdapp", changes)
  550. def test_custom_migration_name(self):
  551. """Tests custom naming of migrations for graph matching."""
  552. # Make a fake graph
  553. graph = MigrationGraph()
  554. graph.add_node(("testapp", "0001_initial"), None)
  555. graph.add_node(("testapp", "0002_foobar"), None)
  556. graph.add_node(("otherapp", "0001_initial"), None)
  557. graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("testapp", "0001_initial"))
  558. # Use project state to make a new migration change set
  559. before = self.make_project_state([])
  560. after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable])
  561. autodetector = MigrationAutodetector(before, after)
  562. changes = autodetector._detect_changes()
  563. # Run through arrange_for_graph
  564. migration_name = 'custom_name'
  565. changes = autodetector.arrange_for_graph(changes, graph, migration_name)
  566. # Make sure there's a new name, deps match, etc.
  567. self.assertEqual(changes["testapp"][0].name, "0003_%s" % migration_name)
  568. self.assertEqual(changes["testapp"][0].dependencies, [("testapp", "0002_foobar")])
  569. self.assertEqual(changes["otherapp"][0].name, "0002_%s" % migration_name)
  570. self.assertEqual(changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")])
  571. def test_new_model(self):
  572. """Tests autodetection of new models."""
  573. # Make state
  574. before = self.make_project_state([])
  575. after = self.make_project_state([self.other_pony_food])
  576. autodetector = MigrationAutodetector(before, after)
  577. changes = autodetector._detect_changes()
  578. # Right number/type of migrations?
  579. self.assertNumberMigrations(changes, 'otherapp', 1)
  580. self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"])
  581. self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Pony")
  582. self.assertEqual([name for name, mgr in changes['otherapp'][0].operations[0].managers],
  583. ['food_qs', 'food_mgr', 'food_mgr_kwargs'])
  584. def test_old_model(self):
  585. """Tests deletion of old models."""
  586. # Make state
  587. before = self.make_project_state([self.author_empty])
  588. after = self.make_project_state([])
  589. autodetector = MigrationAutodetector(before, after)
  590. changes = autodetector._detect_changes()
  591. # Right number/type of migrations?
  592. self.assertNumberMigrations(changes, 'testapp', 1)
  593. self.assertOperationTypes(changes, 'testapp', 0, ["DeleteModel"])
  594. self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author")
  595. def test_add_field(self):
  596. """Tests autodetection of new fields."""
  597. # Make state
  598. before = self.make_project_state([self.author_empty])
  599. after = self.make_project_state([self.author_name])
  600. autodetector = MigrationAutodetector(before, after)
  601. changes = autodetector._detect_changes()
  602. # Right number/type of migrations?
  603. self.assertNumberMigrations(changes, 'testapp', 1)
  604. self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
  605. self.assertOperationAttributes(changes, "testapp", 0, 0, name="name")
  606. def test_remove_field(self):
  607. """Tests autodetection of removed fields."""
  608. # Make state
  609. before = self.make_project_state([self.author_name])
  610. after = self.make_project_state([self.author_empty])
  611. autodetector = MigrationAutodetector(before, after)
  612. changes = autodetector._detect_changes()
  613. # Right number/type of migrations?
  614. self.assertNumberMigrations(changes, 'testapp', 1)
  615. self.assertOperationTypes(changes, 'testapp', 0, ["RemoveField"])
  616. self.assertOperationAttributes(changes, "testapp", 0, 0, name="name")
  617. def test_alter_field(self):
  618. """Tests autodetection of new fields."""
  619. # Make state
  620. before = self.make_project_state([self.author_name])
  621. after = self.make_project_state([self.author_name_longer])
  622. autodetector = MigrationAutodetector(before, after)
  623. changes = autodetector._detect_changes()
  624. # Right number/type of migrations?
  625. self.assertNumberMigrations(changes, 'testapp', 1)
  626. self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
  627. self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=True)
  628. @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration',
  629. side_effect=AssertionError("Should not have prompted for not null addition"))
  630. def test_alter_field_to_not_null_with_default(self, mocked_ask_method):
  631. """
  632. #23609 - Tests autodetection of nullable to non-nullable alterations.
  633. """
  634. # Make state
  635. before = self.make_project_state([self.author_name_null])
  636. after = self.make_project_state([self.author_name_default])
  637. autodetector = MigrationAutodetector(before, after)
  638. changes = autodetector._detect_changes()
  639. # Right number/type of migrations?
  640. self.assertNumberMigrations(changes, 'testapp', 1)
  641. self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
  642. self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=True)
  643. self.assertOperationFieldAttributes(changes, "testapp", 0, 0, default='Ada Lovelace')
  644. @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration',
  645. return_value=models.NOT_PROVIDED)
  646. def test_alter_field_to_not_null_without_default(self, mocked_ask_method):
  647. """
  648. #23609 - Tests autodetection of nullable to non-nullable alterations.
  649. """
  650. # Make state
  651. before = self.make_project_state([self.author_name_null])
  652. after = self.make_project_state([self.author_name])
  653. autodetector = MigrationAutodetector(before, after)
  654. changes = autodetector._detect_changes()
  655. self.assertEqual(mocked_ask_method.call_count, 1)
  656. # Right number/type of migrations?
  657. self.assertNumberMigrations(changes, 'testapp', 1)
  658. self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
  659. self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=True)
  660. self.assertOperationFieldAttributes(changes, "testapp", 0, 0, default=models.NOT_PROVIDED)
  661. @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration',
  662. return_value='Some Name')
  663. def test_alter_field_to_not_null_oneoff_default(self, mocked_ask_method):
  664. """
  665. #23609 - Tests autodetection of nullable to non-nullable alterations.
  666. """
  667. # Make state
  668. before = self.make_project_state([self.author_name_null])
  669. after = self.make_project_state([self.author_name])
  670. autodetector = MigrationAutodetector(before, after)
  671. changes = autodetector._detect_changes()
  672. self.assertEqual(mocked_ask_method.call_count, 1)
  673. # Right number/type of migrations?
  674. self.assertNumberMigrations(changes, 'testapp', 1)
  675. self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
  676. self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=False)
  677. self.assertOperationFieldAttributes(changes, "testapp", 0, 0, default="Some Name")
  678. def test_rename_field(self):
  679. """Tests autodetection of renamed fields."""
  680. # Make state
  681. before = self.make_project_state([self.author_name])
  682. after = self.make_project_state([self.author_name_renamed])
  683. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename": True}))
  684. changes = autodetector._detect_changes()
  685. # Right number/type of migrations?
  686. self.assertNumberMigrations(changes, 'testapp', 1)
  687. self.assertOperationTypes(changes, 'testapp', 0, ["RenameField"])
  688. self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="name", new_name="names")
  689. def test_rename_model(self):
  690. """Tests autodetection of renamed models."""
  691. # Make state
  692. before = self.make_project_state([self.author_with_book, self.book])
  693. after = self.make_project_state([self.author_renamed_with_book, self.book_with_author_renamed])
  694. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True}))
  695. changes = autodetector._detect_changes()
  696. # Right number/type of migrations?
  697. self.assertNumberMigrations(changes, 'testapp', 1)
  698. self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel"])
  699. self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="Author", new_name="Writer")
  700. # Now that RenameModel handles related fields too, there should be
  701. # no AlterField for the related field.
  702. self.assertNumberMigrations(changes, 'otherapp', 0)
  703. def test_rename_model_with_renamed_rel_field(self):
  704. """
  705. Tests autodetection of renamed models while simultaneously renaming one
  706. of the fields that relate to the renamed model.
  707. """
  708. # Make state
  709. before = self.make_project_state([self.author_with_book, self.book])
  710. after = self.make_project_state([self.author_renamed_with_book, self.book_with_field_and_author_renamed])
  711. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({
  712. "ask_rename": True,
  713. "ask_rename_model": True,
  714. }))
  715. changes = autodetector._detect_changes()
  716. # Right number/type of migrations?
  717. self.assertNumberMigrations(changes, 'testapp', 1)
  718. self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel"])
  719. self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="Author", new_name="Writer")
  720. # Right number/type of migrations for related field rename?
  721. # Alter is already taken care of.
  722. self.assertNumberMigrations(changes, 'otherapp', 1)
  723. self.assertOperationTypes(changes, 'otherapp', 0, ["RenameField"])
  724. self.assertOperationAttributes(changes, 'otherapp', 0, 0, old_name="author", new_name="writer")
  725. def test_rename_model_with_fks_in_different_position(self):
  726. """
  727. #24537 - Tests that the order of fields in a model does not influence
  728. the RenameModel detection.
  729. """
  730. before = self.make_project_state([
  731. ModelState("testapp", "EntityA", [
  732. ("id", models.AutoField(primary_key=True)),
  733. ]),
  734. ModelState("testapp", "EntityB", [
  735. ("id", models.AutoField(primary_key=True)),
  736. ("some_label", models.CharField(max_length=255)),
  737. ("entity_a", models.ForeignKey("testapp.EntityA")),
  738. ]),
  739. ])
  740. after = self.make_project_state([
  741. ModelState("testapp", "EntityA", [
  742. ("id", models.AutoField(primary_key=True)),
  743. ]),
  744. ModelState("testapp", "RenamedEntityB", [
  745. ("id", models.AutoField(primary_key=True)),
  746. ("entity_a", models.ForeignKey("testapp.EntityA")),
  747. ("some_label", models.CharField(max_length=255)),
  748. ]),
  749. ])
  750. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True}))
  751. changes = autodetector._detect_changes()
  752. self.assertNumberMigrations(changes, "testapp", 1)
  753. self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"])
  754. self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="EntityB", new_name="RenamedEntityB")
  755. def test_fk_dependency(self):
  756. """Tests that having a ForeignKey automatically adds a dependency."""
  757. # Make state
  758. # Note that testapp (author) has no dependencies,
  759. # otherapp (book) depends on testapp (author),
  760. # thirdapp (edition) depends on otherapp (book)
  761. before = self.make_project_state([])
  762. after = self.make_project_state([self.author_name, self.book, self.edition])
  763. autodetector = MigrationAutodetector(before, after)
  764. changes = autodetector._detect_changes()
  765. # Right number/type of migrations?
  766. self.assertNumberMigrations(changes, 'testapp', 1)
  767. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"])
  768. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  769. self.assertMigrationDependencies(changes, 'testapp', 0, [])
  770. # Right number/type of migrations?
  771. self.assertNumberMigrations(changes, 'otherapp', 1)
  772. self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"])
  773. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book")
  774. self.assertMigrationDependencies(changes, 'otherapp', 0, [("testapp", "auto_1")])
  775. # Right number/type of migrations?
  776. self.assertNumberMigrations(changes, 'thirdapp', 1)
  777. self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel"])
  778. self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="Edition")
  779. self.assertMigrationDependencies(changes, 'thirdapp', 0, [("otherapp", "auto_1")])
  780. def test_proxy_fk_dependency(self):
  781. """Tests that FK dependencies still work on proxy models."""
  782. # Make state
  783. # Note that testapp (author) has no dependencies,
  784. # otherapp (book) depends on testapp (authorproxy)
  785. before = self.make_project_state([])
  786. after = self.make_project_state([self.author_empty, self.author_proxy_third, self.book_proxy_fk])
  787. autodetector = MigrationAutodetector(before, after)
  788. changes = autodetector._detect_changes()
  789. # Right number/type of migrations?
  790. self.assertNumberMigrations(changes, 'testapp', 1)
  791. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"])
  792. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  793. self.assertMigrationDependencies(changes, 'testapp', 0, [])
  794. # Right number/type of migrations?
  795. self.assertNumberMigrations(changes, 'otherapp', 1)
  796. self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"])
  797. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book")
  798. self.assertMigrationDependencies(changes, 'otherapp', 0, [("thirdapp", "auto_1")])
  799. # Right number/type of migrations?
  800. self.assertNumberMigrations(changes, 'thirdapp', 1)
  801. self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel"])
  802. self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="AuthorProxy")
  803. self.assertMigrationDependencies(changes, 'thirdapp', 0, [("testapp", "auto_1")])
  804. def test_same_app_no_fk_dependency(self):
  805. """
  806. Tests that a migration with a FK between two models of the same app
  807. does not have a dependency to itself.
  808. """
  809. # Make state
  810. before = self.make_project_state([])
  811. after = self.make_project_state([self.author_with_publisher, self.publisher])
  812. autodetector = MigrationAutodetector(before, after)
  813. changes = autodetector._detect_changes()
  814. # Right number/type of migrations?
  815. self.assertNumberMigrations(changes, 'testapp', 1)
  816. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel", "AddField"])
  817. self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author")
  818. self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher")
  819. self.assertOperationAttributes(changes, "testapp", 0, 2, name="publisher")
  820. self.assertMigrationDependencies(changes, 'testapp', 0, [])
  821. def test_circular_fk_dependency(self):
  822. """
  823. Tests that having a circular ForeignKey dependency automatically
  824. resolves the situation into 2 migrations on one side and 1 on the other.
  825. """
  826. # Make state
  827. before = self.make_project_state([])
  828. after = self.make_project_state([self.author_with_book, self.book, self.publisher_with_book])
  829. autodetector = MigrationAutodetector(before, after)
  830. changes = autodetector._detect_changes()
  831. # Right number/type of migrations?
  832. self.assertNumberMigrations(changes, 'testapp', 1)
  833. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"])
  834. self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author")
  835. self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher")
  836. self.assertMigrationDependencies(changes, 'testapp', 0, [("otherapp", "auto_1")])
  837. # Right number/type of migrations?
  838. self.assertNumberMigrations(changes, 'otherapp', 2)
  839. self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"])
  840. self.assertOperationTypes(changes, 'otherapp', 1, ["AddField"])
  841. self.assertMigrationDependencies(changes, 'otherapp', 0, [])
  842. self.assertMigrationDependencies(changes, 'otherapp', 1, [("otherapp", "auto_1"), ("testapp", "auto_1")])
  843. # both split migrations should be `initial`
  844. self.assertTrue(changes['otherapp'][0].initial)
  845. self.assertTrue(changes['otherapp'][1].initial)
  846. def test_same_app_circular_fk_dependency(self):
  847. """
  848. Tests that a migration with a FK between two models of the same app does
  849. not have a dependency to itself.
  850. """
  851. # Make state
  852. before = self.make_project_state([])
  853. after = self.make_project_state([self.author_with_publisher, self.publisher_with_author])
  854. autodetector = MigrationAutodetector(before, after)
  855. changes = autodetector._detect_changes()
  856. # Right number/type of migrations?
  857. self.assertNumberMigrations(changes, 'testapp', 1)
  858. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel", "AddField"])
  859. self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author")
  860. self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher")
  861. self.assertOperationAttributes(changes, "testapp", 0, 2, name="publisher")
  862. self.assertMigrationDependencies(changes, 'testapp', 0, [])
  863. def test_same_app_circular_fk_dependency_and_unique_together(self):
  864. """
  865. #22275 - Tests that a migration with circular FK dependency does not try
  866. to create unique together constraint before creating all required fields
  867. first.
  868. """
  869. # Make state
  870. before = self.make_project_state([])
  871. after = self.make_project_state([self.knight, self.rabbit])
  872. autodetector = MigrationAutodetector(before, after)
  873. changes = autodetector._detect_changes()
  874. # Right number/type of migrations?
  875. self.assertNumberMigrations(changes, 'eggs', 1)
  876. self.assertOperationTypes(changes, 'eggs', 0, ["CreateModel", "CreateModel", "AlterUniqueTogether"])
  877. self.assertNotIn("unique_together", changes['eggs'][0].operations[0].options)
  878. self.assertNotIn("unique_together", changes['eggs'][0].operations[1].options)
  879. self.assertMigrationDependencies(changes, 'eggs', 0, [])
  880. def test_alter_db_table_add(self):
  881. """Tests detection for adding db_table in model's options."""
  882. # Make state
  883. before = self.make_project_state([self.author_empty])
  884. after = self.make_project_state([self.author_with_db_table_options])
  885. autodetector = MigrationAutodetector(before, after)
  886. changes = autodetector._detect_changes()
  887. # Right number/type of migrations?
  888. self.assertNumberMigrations(changes, 'testapp', 1)
  889. self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelTable"])
  890. self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", table="author_one")
  891. def test_alter_db_table_change(self):
  892. """Tests detection for changing db_table in model's options'."""
  893. # Make state
  894. before = self.make_project_state([self.author_with_db_table_options])
  895. after = self.make_project_state([self.author_with_new_db_table_options])
  896. autodetector = MigrationAutodetector(before, after)
  897. changes = autodetector._detect_changes()
  898. # Right number/type of migrations?
  899. self.assertNumberMigrations(changes, 'testapp', 1)
  900. self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelTable"])
  901. self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", table="author_two")
  902. def test_alter_db_table_remove(self):
  903. """Tests detection for removing db_table in model's options."""
  904. # Make state
  905. before = self.make_project_state([self.author_with_db_table_options])
  906. after = self.make_project_state([self.author_empty])
  907. autodetector = MigrationAutodetector(before, after)
  908. changes = autodetector._detect_changes()
  909. # Right number/type of migrations?
  910. self.assertNumberMigrations(changes, 'testapp', 1)
  911. self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelTable"])
  912. self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", table=None)
  913. def test_alter_db_table_no_changes(self):
  914. """
  915. Tests that alter_db_table doesn't generate a migration if no changes
  916. have been made.
  917. """
  918. # Make state
  919. before = self.make_project_state([self.author_with_db_table_options])
  920. after = self.make_project_state([self.author_with_db_table_options])
  921. autodetector = MigrationAutodetector(before, after)
  922. changes = autodetector._detect_changes()
  923. # Right number of migrations?
  924. self.assertEqual(len(changes), 0)
  925. def test_keep_db_table_with_model_change(self):
  926. """
  927. Tests when model changes but db_table stays as-is, autodetector must not
  928. create more than one operation.
  929. """
  930. # Make state
  931. before = self.make_project_state([self.author_with_db_table_options])
  932. after = self.make_project_state([self.author_renamed_with_db_table_options])
  933. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True}))
  934. changes = autodetector._detect_changes()
  935. # Right number/type of migrations?
  936. self.assertNumberMigrations(changes, 'testapp', 1)
  937. self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel"])
  938. self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor")
  939. def test_alter_db_table_with_model_change(self):
  940. """
  941. Tests when model and db_table changes, autodetector must create two
  942. operations.
  943. """
  944. # Make state
  945. before = self.make_project_state([self.author_with_db_table_options])
  946. after = self.make_project_state([self.author_renamed_with_new_db_table_options])
  947. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True}))
  948. changes = autodetector._detect_changes()
  949. # Right number/type of migrations?
  950. self.assertNumberMigrations(changes, 'testapp', 1)
  951. self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel", "AlterModelTable"])
  952. self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor")
  953. self.assertOperationAttributes(changes, "testapp", 0, 1, name="newauthor", table="author_three")
  954. def test_empty_foo_together(self):
  955. """
  956. #23452 - Empty unique/index_together shouldn't generate a migration.
  957. """
  958. # Explicitly testing for not specified, since this is the case after
  959. # a CreateModel operation w/o any definition on the original model
  960. model_state_not_secified = ModelState("a", "model", [("id", models.AutoField(primary_key=True))])
  961. # Explicitly testing for None, since this was the issue in #23452 after
  962. # a AlterFooTogether operation with e.g. () as value
  963. model_state_none = ModelState("a", "model", [
  964. ("id", models.AutoField(primary_key=True))
  965. ], {
  966. "index_together": None,
  967. "unique_together": None,
  968. })
  969. # Explicitly testing for the empty set, since we now always have sets.
  970. # During removal (('col1', 'col2'),) --> () this becomes set([])
  971. model_state_empty = ModelState("a", "model", [
  972. ("id", models.AutoField(primary_key=True))
  973. ], {
  974. "index_together": set(),
  975. "unique_together": set(),
  976. })
  977. def test(from_state, to_state, msg):
  978. before = self.make_project_state([from_state])
  979. after = self.make_project_state([to_state])
  980. autodetector = MigrationAutodetector(before, after)
  981. changes = autodetector._detect_changes()
  982. if len(changes) > 0:
  983. ops = ', '.join(o.__class__.__name__ for o in changes['a'][0].operations)
  984. self.fail('Created operation(s) %s from %s' % (ops, msg))
  985. tests = (
  986. (model_state_not_secified, model_state_not_secified, '"not specified" to "not specified"'),
  987. (model_state_not_secified, model_state_none, '"not specified" to "None"'),
  988. (model_state_not_secified, model_state_empty, '"not specified" to "empty"'),
  989. (model_state_none, model_state_not_secified, '"None" to "not specified"'),
  990. (model_state_none, model_state_none, '"None" to "None"'),
  991. (model_state_none, model_state_empty, '"None" to "empty"'),
  992. (model_state_empty, model_state_not_secified, '"empty" to "not specified"'),
  993. (model_state_empty, model_state_none, '"empty" to "None"'),
  994. (model_state_empty, model_state_empty, '"empty" to "empty"'),
  995. )
  996. for t in tests:
  997. test(*t)
  998. def test_add_foo_together(self):
  999. """Tests index/unique_together detection."""
  1000. # Make state
  1001. before = self.make_project_state([self.author_empty, self.book])
  1002. after = self.make_project_state([self.author_empty, self.book_foo_together])
  1003. autodetector = MigrationAutodetector(before, after)
  1004. changes = autodetector._detect_changes()
  1005. # Right number/type of migrations?
  1006. self.assertNumberMigrations(changes, "otherapp", 1)
  1007. self.assertOperationTypes(changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"])
  1008. self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together={("author", "title")})
  1009. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together={("author", "title")})
  1010. def test_remove_foo_together(self):
  1011. """Tests index/unique_together detection."""
  1012. before = self.make_project_state([self.author_empty, self.book_foo_together])
  1013. after = self.make_project_state([self.author_empty, self.book])
  1014. autodetector = MigrationAutodetector(before, after)
  1015. changes = autodetector._detect_changes()
  1016. # Right number/type of migrations?
  1017. self.assertNumberMigrations(changes, "otherapp", 1)
  1018. self.assertOperationTypes(changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"])
  1019. self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together=set())
  1020. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together=set())
  1021. def test_foo_together_remove_fk(self):
  1022. """Tests unique_together and field removal detection & ordering"""
  1023. # Make state
  1024. before = self.make_project_state([self.author_empty, self.book_foo_together])
  1025. after = self.make_project_state([self.author_empty, self.book_with_no_author])
  1026. autodetector = MigrationAutodetector(before, after)
  1027. changes = autodetector._detect_changes()
  1028. # Right number/type of migrations?
  1029. self.assertNumberMigrations(changes, "otherapp", 1)
  1030. self.assertOperationTypes(changes, "otherapp", 0, [
  1031. "AlterUniqueTogether", "AlterIndexTogether", "RemoveField"
  1032. ])
  1033. self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together=set())
  1034. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together=set())
  1035. self.assertOperationAttributes(changes, "otherapp", 0, 2, model_name="book", name="author")
  1036. def test_foo_together_no_changes(self):
  1037. """
  1038. Tests that index/unique_together doesn't generate a migration if no
  1039. changes have been made.
  1040. """
  1041. # Make state
  1042. before = self.make_project_state([self.author_empty, self.book_foo_together])
  1043. after = self.make_project_state([self.author_empty, self.book_foo_together])
  1044. autodetector = MigrationAutodetector(before, after)
  1045. changes = autodetector._detect_changes()
  1046. # Right number of migrations?
  1047. self.assertEqual(len(changes), 0)
  1048. def test_foo_together_ordering(self):
  1049. """
  1050. Tests that index/unique_together also triggers on ordering changes.
  1051. """
  1052. # Make state
  1053. before = self.make_project_state([self.author_empty, self.book_foo_together])
  1054. after = self.make_project_state([self.author_empty, self.book_foo_together_2])
  1055. autodetector = MigrationAutodetector(before, after)
  1056. changes = autodetector._detect_changes()
  1057. # Right number/type of migrations?
  1058. self.assertNumberMigrations(changes, "otherapp", 1)
  1059. self.assertOperationTypes(changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"])
  1060. self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together={("title", "author")})
  1061. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together={("title", "author")})
  1062. def test_add_field_and_foo_together(self):
  1063. """
  1064. Tests that added fields will be created before using them in
  1065. index/unique_together.
  1066. """
  1067. before = self.make_project_state([self.author_empty, self.book])
  1068. after = self.make_project_state([self.author_empty, self.book_foo_together_3])
  1069. autodetector = MigrationAutodetector(before, after)
  1070. changes = autodetector._detect_changes()
  1071. # Right number/type of migrations?
  1072. self.assertNumberMigrations(changes, "otherapp", 1)
  1073. self.assertOperationTypes(changes, "otherapp", 0, ["AddField", "AlterUniqueTogether", "AlterIndexTogether"])
  1074. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", unique_together={("title", "newfield")})
  1075. self.assertOperationAttributes(changes, "otherapp", 0, 2, name="book", index_together={("title", "newfield")})
  1076. def test_remove_field_and_foo_together(self):
  1077. """
  1078. Tests that removed fields will be removed after updating
  1079. index/unique_together.
  1080. """
  1081. before = self.make_project_state([self.author_empty, self.book_foo_together_3])
  1082. after = self.make_project_state([self.author_empty, self.book_foo_together])
  1083. autodetector = MigrationAutodetector(before, after)
  1084. changes = autodetector._detect_changes()
  1085. # Right number/type of migrations?
  1086. self.assertNumberMigrations(changes, "otherapp", 1)
  1087. self.assertOperationTypes(changes, "otherapp", 0, ["RemoveField", "AlterUniqueTogether", "AlterIndexTogether"])
  1088. self.assertOperationAttributes(changes, "otherapp", 0, 0, model_name="book", name="newfield")
  1089. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", unique_together={("author", "title")})
  1090. self.assertOperationAttributes(changes, "otherapp", 0, 2, name="book", index_together={("author", "title")})
  1091. def test_rename_field_and_foo_together(self):
  1092. """
  1093. Tests that removed fields will be removed after updating
  1094. index/unique_together.
  1095. """
  1096. before = self.make_project_state([self.author_empty, self.book_foo_together_3])
  1097. after = self.make_project_state([self.author_empty, self.book_foo_together_4])
  1098. autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename": True}))
  1099. changes = autodetector._detect_changes()
  1100. # Right number/type of migrations?
  1101. self.assertNumberMigrations(changes, "otherapp", 1)
  1102. self.assertOperationTypes(changes, "otherapp", 0, ["RenameField", "AlterUniqueTogether", "AlterIndexTogether"])
  1103. self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", unique_together={
  1104. ("title", "newfield2")
  1105. })
  1106. self.assertOperationAttributes(changes, "otherapp", 0, 2, name="book", index_together={("title", "newfield2")})
  1107. def test_proxy(self):
  1108. """Tests that the autodetector correctly deals with proxy models."""
  1109. # First, we test adding a proxy model
  1110. before = self.make_project_state([self.author_empty])
  1111. after = self.make_project_state([self.author_empty, self.author_proxy])
  1112. autodetector = MigrationAutodetector(before, after)
  1113. changes = autodetector._detect_changes()
  1114. # Right number/type of migrations?
  1115. self.assertNumberMigrations(changes, "testapp", 1)
  1116. self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"])
  1117. self.assertOperationAttributes(changes, "testapp", 0, 0, name="AuthorProxy", options={"proxy": True})
  1118. # Now, we test turning a proxy model into a non-proxy model
  1119. # It should delete the proxy then make the real one
  1120. before = self.make_project_state([self.author_empty, self.author_proxy])
  1121. after = self.make_project_state([self.author_empty, self.author_proxy_notproxy])
  1122. autodetector = MigrationAutodetector(before, after)
  1123. changes = autodetector._detect_changes()
  1124. # Right number/type of migrations?
  1125. self.assertNumberMigrations(changes, "testapp", 1)
  1126. self.assertOperationTypes(changes, "testapp", 0, ["DeleteModel", "CreateModel"])
  1127. self.assertOperationAttributes(changes, "testapp", 0, 0, name="AuthorProxy")
  1128. self.assertOperationAttributes(changes, "testapp", 0, 1, name="AuthorProxy", options={})
  1129. def test_proxy_custom_pk(self):
  1130. """
  1131. #23415 - The autodetector must correctly deal with custom FK on proxy
  1132. models.
  1133. """
  1134. # First, we test the default pk field name
  1135. before = self.make_project_state([])
  1136. after = self.make_project_state([self.author_empty, self.author_proxy_third, self.book_proxy_fk])
  1137. autodetector = MigrationAutodetector(before, after)
  1138. changes = autodetector._detect_changes()
  1139. # The field name the FK on the book model points to
  1140. self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'id')
  1141. # Now, we test the custom pk field name
  1142. before = self.make_project_state([])
  1143. after = self.make_project_state([self.author_custom_pk, self.author_proxy_third, self.book_proxy_fk])
  1144. autodetector = MigrationAutodetector(before, after)
  1145. changes = autodetector._detect_changes()
  1146. # The field name the FK on the book model points to
  1147. self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'pk_field')
  1148. def test_unmanaged_create(self):
  1149. """Tests that the autodetector correctly deals with managed models."""
  1150. # First, we test adding an unmanaged model
  1151. before = self.make_project_state([self.author_empty])
  1152. after = self.make_project_state([self.author_empty, self.author_unmanaged])
  1153. autodetector = MigrationAutodetector(before, after)
  1154. changes = autodetector._detect_changes()
  1155. # Right number/type of migrations?
  1156. self.assertNumberMigrations(changes, 'testapp', 1)
  1157. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"])
  1158. self.assertOperationAttributes(changes, 'testapp', 0, 0,
  1159. name="AuthorUnmanaged", options={"managed": False})
  1160. def test_unmanaged_to_managed(self):
  1161. # Now, we test turning an unmanaged model into a managed model
  1162. before = self.make_project_state([self.author_empty, self.author_unmanaged])
  1163. after = self.make_project_state([self.author_empty, self.author_unmanaged_managed])
  1164. autodetector = MigrationAutodetector(before, after)
  1165. changes = autodetector._detect_changes()
  1166. # Right number/type of migrations?
  1167. self.assertNumberMigrations(changes, 'testapp', 1)
  1168. self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelOptions"])
  1169. self.assertOperationAttributes(changes, 'testapp', 0, 0,
  1170. name="authorunmanaged", options={})
  1171. def test_managed_to_unmanaged(self):
  1172. # Now, we turn managed to unmanaged.
  1173. before = self.make_project_state([self.author_empty, self.author_unmanaged_managed])
  1174. after = self.make_project_state([self.author_empty, self.author_unmanaged])
  1175. autodetector = MigrationAutodetector(before, after)
  1176. changes = autodetector._detect_changes()
  1177. # Right number/type of migrations?
  1178. self.assertNumberMigrations(changes, 'testapp', 1)
  1179. self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"])
  1180. self.assertOperationAttributes(changes, "testapp", 0, 0,
  1181. name="authorunmanaged", options={"managed": False})
  1182. def test_unmanaged_custom_pk(self):
  1183. """
  1184. #23415 - The autodetector must correctly deal with custom FK on
  1185. unmanaged models.
  1186. """
  1187. # First, we test the default pk field name
  1188. before = self.make_project_state([])
  1189. after = self.make_project_state([self.author_unmanaged_default_pk, self.book])
  1190. autodetector = MigrationAutodetector(before, after)
  1191. changes = autodetector._detect_changes()
  1192. # The field name the FK on the book model points to
  1193. self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'id')
  1194. # Now, we test the custom pk field name
  1195. before = self.make_project_state([])
  1196. after = self.make_project_state([self.author_unmanaged_custom_pk, self.book])
  1197. autodetector = MigrationAutodetector(before, after)
  1198. changes = autodetector._detect_changes()
  1199. # The field name the FK on the book model points to
  1200. self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'pk_field')
  1201. @override_settings(AUTH_USER_MODEL="thirdapp.CustomUser")
  1202. def test_swappable(self):
  1203. before = self.make_project_state([self.custom_user])
  1204. after = self.make_project_state([self.custom_user, self.author_with_custom_user])
  1205. autodetector = MigrationAutodetector(before, after)
  1206. changes = autodetector._detect_changes()
  1207. # Right number/type of migrations?
  1208. self.assertNumberMigrations(changes, 'testapp', 1)
  1209. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"])
  1210. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  1211. self.assertMigrationDependencies(changes, 'testapp', 0, [("__setting__", "AUTH_USER_MODEL")])
  1212. def test_swappable_changed(self):
  1213. before = self.make_project_state([self.custom_user, self.author_with_user])
  1214. with override_settings(AUTH_USER_MODEL="thirdapp.CustomUser"):
  1215. after = self.make_project_state([self.custom_user, self.author_with_custom_user])
  1216. autodetector = MigrationAutodetector(before, after)
  1217. changes = autodetector._detect_changes()
  1218. # Right number/type of migrations?
  1219. self.assertNumberMigrations(changes, 'testapp', 1)
  1220. self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
  1221. self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name='user')
  1222. fk_field = changes['testapp'][0].operations[0].field
  1223. to_model = '%s.%s' % (fk_field.remote_field.model._meta.app_label, fk_field.remote_field.model._meta.object_name)
  1224. self.assertEqual(to_model, 'thirdapp.CustomUser')
  1225. def test_add_field_with_default(self):
  1226. """#22030 - Adding a field with a default should work."""
  1227. # Make state
  1228. before = self.make_project_state([self.author_empty])
  1229. after = self.make_project_state([self.author_name_default])
  1230. autodetector = MigrationAutodetector(before, after)
  1231. changes = autodetector._detect_changes()
  1232. # Right number/type of migrations?
  1233. self.assertNumberMigrations(changes, 'testapp', 1)
  1234. self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
  1235. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="name")
  1236. def test_custom_deconstructable(self):
  1237. """
  1238. Two instances which deconstruct to the same value aren't considered a
  1239. change.
  1240. """
  1241. before = self.make_project_state([self.author_name_deconstructable_1])
  1242. after = self.make_project_state([self.author_name_deconstructable_2])
  1243. autodetector = MigrationAutodetector(before, after)
  1244. changes = autodetector._detect_changes()
  1245. # Right number of migrations?
  1246. self.assertEqual(len(changes), 0)
  1247. def test_deconstruct_field_kwarg(self):
  1248. """Field instances are handled correctly by nested deconstruction."""
  1249. before = self.make_project_state([self.author_name_deconstructable_3])
  1250. after = self.make_project_state([self.author_name_deconstructable_4])
  1251. autodetector = MigrationAutodetector(before, after)
  1252. changes = autodetector._detect_changes()
  1253. self.assertEqual(changes, {})
  1254. def test_deconstructable_list(self):
  1255. """Nested deconstruction descends into lists."""
  1256. # When lists contain items that deconstruct to identical values, those lists
  1257. # should be considered equal for the purpose of detecting state changes
  1258. # (even if the original items are unequal).
  1259. before = self.make_project_state([self.author_name_deconstructable_list_1])
  1260. after = self.make_project_state([self.author_name_deconstructable_list_2])
  1261. autodetector = MigrationAutodetector(before, after)
  1262. changes = autodetector._detect_changes()
  1263. self.assertEqual(changes, {})
  1264. # Legitimate differences within the deconstructed lists should be reported
  1265. # as a change
  1266. before = self.make_project_state([self.author_name_deconstructable_list_1])
  1267. after = self.make_project_state([self.author_name_deconstructable_list_3])
  1268. autodetector = MigrationAutodetector(before, after)
  1269. changes = autodetector._detect_changes()
  1270. self.assertEqual(len(changes), 1)
  1271. def test_deconstructable_tuple(self):
  1272. """Nested deconstruction descends into tuples."""
  1273. # When tuples contain items that deconstruct to identical values, those tuples
  1274. # should be considered equal for the purpose of detecting state changes
  1275. # (even if the original items are unequal).
  1276. before = self.make_project_state([self.author_name_deconstructable_tuple_1])
  1277. after = self.make_project_state([self.author_name_deconstructable_tuple_2])
  1278. autodetector = MigrationAutodetector(before, after)
  1279. changes = autodetector._detect_changes()
  1280. self.assertEqual(changes, {})
  1281. # Legitimate differences within the deconstructed tuples should be reported
  1282. # as a change
  1283. before = self.make_project_state([self.author_name_deconstructable_tuple_1])
  1284. after = self.make_project_state([self.author_name_deconstructable_tuple_3])
  1285. autodetector = MigrationAutodetector(before, after)
  1286. changes = autodetector._detect_changes()
  1287. self.assertEqual(len(changes), 1)
  1288. def test_deconstructable_dict(self):
  1289. """Nested deconstruction descends into dict values."""
  1290. # When dicts contain items whose values deconstruct to identical values,
  1291. # those dicts should be considered equal for the purpose of detecting
  1292. # state changes (even if the original values are unequal).
  1293. before = self.make_project_state([self.author_name_deconstructable_dict_1])
  1294. after = self.make_project_state([self.author_name_deconstructable_dict_2])
  1295. autodetector = MigrationAutodetector(before, after)
  1296. changes = autodetector._detect_changes()
  1297. self.assertEqual(changes, {})
  1298. # Legitimate differences within the deconstructed dicts should be reported
  1299. # as a change
  1300. before = self.make_project_state([self.author_name_deconstructable_dict_1])
  1301. after = self.make_project_state([self.author_name_deconstructable_dict_3])
  1302. autodetector = MigrationAutodetector(before, after)
  1303. changes = autodetector._detect_changes()
  1304. self.assertEqual(len(changes), 1)
  1305. def test_nested_deconstructable_objects(self):
  1306. """
  1307. Nested deconstruction is applied recursively to the args/kwargs of
  1308. deconstructed objects.
  1309. """
  1310. # If the items within a deconstructed object's args/kwargs have the same
  1311. # deconstructed values - whether or not the items themselves are different
  1312. # instances - then the object as a whole is regarded as unchanged.
  1313. before = self.make_project_state([self.author_name_nested_deconstructable_1])
  1314. after = self.make_project_state([self.author_name_nested_deconstructable_2])
  1315. autodetector = MigrationAutodetector(before, after)
  1316. changes = autodetector._detect_changes()
  1317. self.assertEqual(changes, {})
  1318. # Differences that exist solely within the args list of a deconstructed object
  1319. # should be reported as changes
  1320. before = self.make_project_state([self.author_name_nested_deconstructable_1])
  1321. after = self.make_project_state([self.author_name_nested_deconstructable_changed_arg])
  1322. autodetector = MigrationAutodetector(before, after)
  1323. changes = autodetector._detect_changes()
  1324. self.assertEqual(len(changes), 1)
  1325. # Additional args should also be reported as a change
  1326. before = self.make_project_state([self.author_name_nested_deconstructable_1])
  1327. after = self.make_project_state([self.author_name_nested_deconstructable_extra_arg])
  1328. autodetector = MigrationAutodetector(before, after)
  1329. changes = autodetector._detect_changes()
  1330. self.assertEqual(len(changes), 1)
  1331. # Differences that exist solely within the kwargs dict of a deconstructed object
  1332. # should be reported as changes
  1333. before = self.make_project_state([self.author_name_nested_deconstructable_1])
  1334. after = self.make_project_state([self.author_name_nested_deconstructable_changed_kwarg])
  1335. autodetector = MigrationAutodetector(before, after)
  1336. changes = autodetector._detect_changes()
  1337. self.assertEqual(len(changes), 1)
  1338. # Additional kwargs should also be reported as a change
  1339. before = self.make_project_state([self.author_name_nested_deconstructable_1])
  1340. after = self.make_project_state([self.author_name_nested_deconstructable_extra_kwarg])
  1341. autodetector = MigrationAutodetector(before, after)
  1342. changes = autodetector._detect_changes()
  1343. self.assertEqual(len(changes), 1)
  1344. def test_deconstruct_type(self):
  1345. """
  1346. #22951 -- Uninstanted classes with deconstruct are correctly returned
  1347. by deep_deconstruct during serialization.
  1348. """
  1349. author = ModelState(
  1350. "testapp",
  1351. "Author",
  1352. [
  1353. ("id", models.AutoField(primary_key=True)),
  1354. ("name", models.CharField(
  1355. max_length=200,
  1356. # IntegerField intentionally not instantiated.
  1357. default=models.IntegerField,
  1358. ))
  1359. ],
  1360. )
  1361. # Make state
  1362. before = self.make_project_state([])
  1363. after = self.make_project_state([author])
  1364. autodetector = MigrationAutodetector(before, after)
  1365. changes = autodetector._detect_changes()
  1366. # Right number/type of migrations?
  1367. self.assertNumberMigrations(changes, 'testapp', 1)
  1368. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"])
  1369. def test_replace_string_with_foreignkey(self):
  1370. """
  1371. #22300 - Adding an FK in the same "spot" as a deleted CharField should
  1372. work.
  1373. """
  1374. # Make state
  1375. before = self.make_project_state([self.author_with_publisher_string])
  1376. after = self.make_project_state([self.author_with_publisher, self.publisher])
  1377. autodetector = MigrationAutodetector(before, after)
  1378. changes = autodetector._detect_changes()
  1379. # Right number/type of migrations?
  1380. self.assertNumberMigrations(changes, 'testapp', 1)
  1381. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "RemoveField", "AddField"])
  1382. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Publisher")
  1383. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publisher_name")
  1384. self.assertOperationAttributes(changes, 'testapp', 0, 2, name="publisher")
  1385. def test_foreign_key_removed_before_target_model(self):
  1386. """
  1387. Removing an FK and the model it targets in the same change must remove
  1388. the FK field before the model to maintain consistency.
  1389. """
  1390. before = self.make_project_state([self.author_with_publisher, self.publisher])
  1391. after = self.make_project_state([self.author_name]) # removes both the model and FK
  1392. autodetector = MigrationAutodetector(before, after)
  1393. changes = autodetector._detect_changes()
  1394. # Right number/type of migrations?
  1395. self.assertNumberMigrations(changes, 'testapp', 1)
  1396. self.assertOperationTypes(changes, 'testapp', 0, ["RemoveField", "DeleteModel"])
  1397. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publisher")
  1398. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Publisher")
  1399. @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition',
  1400. side_effect=AssertionError("Should not have prompted for not null addition"))
  1401. def test_add_many_to_many(self, mocked_ask_method):
  1402. """#22435 - Adding a ManyToManyField should not prompt for a default."""
  1403. before = self.make_project_state([self.author_empty, self.publisher])
  1404. after = self.make_project_state([self.author_with_m2m, self.publisher])
  1405. autodetector = MigrationAutodetector(before, after)
  1406. changes = autodetector._detect_changes()
  1407. # Right number/type of migrations?
  1408. self.assertNumberMigrations(changes, 'testapp', 1)
  1409. self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
  1410. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers")
  1411. def test_alter_many_to_many(self):
  1412. before = self.make_project_state([self.author_with_m2m, self.publisher])
  1413. after = self.make_project_state([self.author_with_m2m_blank, self.publisher])
  1414. autodetector = MigrationAutodetector(before, after)
  1415. changes = autodetector._detect_changes()
  1416. # Right number/type of migrations?
  1417. self.assertNumberMigrations(changes, 'testapp', 1)
  1418. self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
  1419. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers")
  1420. def test_create_with_through_model(self):
  1421. """
  1422. Adding a m2m with a through model and the models that use it should be
  1423. ordered correctly.
  1424. """
  1425. before = self.make_project_state([])
  1426. after = self.make_project_state([self.author_with_m2m_through, self.publisher, self.contract])
  1427. autodetector = MigrationAutodetector(before, after)
  1428. changes = autodetector._detect_changes()
  1429. # Right number/type of migrations?
  1430. self.assertNumberMigrations(changes, "testapp", 1)
  1431. self.assertOperationTypes(changes, "testapp", 0, [
  1432. "CreateModel", "CreateModel", "CreateModel", "AddField", "AddField"
  1433. ])
  1434. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  1435. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Contract")
  1436. self.assertOperationAttributes(changes, 'testapp', 0, 2, name="Publisher")
  1437. self.assertOperationAttributes(changes, 'testapp', 0, 3, model_name='contract', name='publisher')
  1438. self.assertOperationAttributes(changes, 'testapp', 0, 4, model_name='author', name='publishers')
  1439. def test_many_to_many_removed_before_through_model(self):
  1440. """
  1441. Removing a ManyToManyField and the "through" model in the same change
  1442. must remove the field before the model to maintain consistency.
  1443. """
  1444. before = self.make_project_state([
  1445. self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution
  1446. ])
  1447. # Remove both the through model and ManyToMany
  1448. after = self.make_project_state([self.book_with_no_author, self.author_name])
  1449. autodetector = MigrationAutodetector(before, after)
  1450. changes = autodetector._detect_changes()
  1451. # Right number/type of migrations?
  1452. self.assertNumberMigrations(changes, "otherapp", 1)
  1453. self.assertOperationTypes(changes, "otherapp", 0, ["RemoveField", "RemoveField", "RemoveField", "DeleteModel"])
  1454. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="author", model_name='attribution')
  1455. self.assertOperationAttributes(changes, 'otherapp', 0, 1, name="book", model_name='attribution')
  1456. self.assertOperationAttributes(changes, 'otherapp', 0, 2, name="authors", model_name='book')
  1457. self.assertOperationAttributes(changes, 'otherapp', 0, 3, name='Attribution')
  1458. def test_many_to_many_removed_before_through_model_2(self):
  1459. """
  1460. Removing a model that contains a ManyToManyField and the "through" model
  1461. in the same change must remove the field before the model to maintain
  1462. consistency.
  1463. """
  1464. before = self.make_project_state([
  1465. self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution
  1466. ])
  1467. # Remove both the through model and ManyToMany
  1468. after = self.make_project_state([self.author_name])
  1469. autodetector = MigrationAutodetector(before, after)
  1470. changes = autodetector._detect_changes()
  1471. # Right number/type of migrations?
  1472. self.assertNumberMigrations(changes, "otherapp", 1)
  1473. self.assertOperationTypes(changes, "otherapp", 0, [
  1474. "RemoveField", "RemoveField", "RemoveField", "DeleteModel", "DeleteModel"
  1475. ])
  1476. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="author", model_name='attribution')
  1477. self.assertOperationAttributes(changes, 'otherapp', 0, 1, name="book", model_name='attribution')
  1478. self.assertOperationAttributes(changes, 'otherapp', 0, 2, name="authors", model_name='book')
  1479. self.assertOperationAttributes(changes, 'otherapp', 0, 3, name='Attribution')
  1480. self.assertOperationAttributes(changes, 'otherapp', 0, 4, name='Book')
  1481. def test_m2m_w_through_multistep_remove(self):
  1482. """
  1483. A model with a m2m field that specifies a "through" model cannot be
  1484. removed in the same migration as that through model as the schema will
  1485. pass through an inconsistent state. The autodetector should produce two
  1486. migrations to avoid this issue.
  1487. """
  1488. before = self.make_project_state([self.author_with_m2m_through, self.publisher, self.contract])
  1489. after = self.make_project_state([self.publisher])
  1490. autodetector = MigrationAutodetector(before, after)
  1491. changes = autodetector._detect_changes()
  1492. # Right number/type of migrations?
  1493. self.assertNumberMigrations(changes, "testapp", 1)
  1494. self.assertOperationTypes(changes, "testapp", 0, [
  1495. "RemoveField", "RemoveField", "RemoveField", "DeleteModel", "DeleteModel"
  1496. ])
  1497. self.assertOperationAttributes(changes, "testapp", 0, 0, name="publishers", model_name='author')
  1498. self.assertOperationAttributes(changes, "testapp", 0, 1, name="author", model_name='contract')
  1499. self.assertOperationAttributes(changes, "testapp", 0, 2, name="publisher", model_name='contract')
  1500. self.assertOperationAttributes(changes, "testapp", 0, 3, name="Author")
  1501. self.assertOperationAttributes(changes, "testapp", 0, 4, name="Contract")
  1502. def test_concrete_field_changed_to_many_to_many(self):
  1503. """
  1504. #23938 - Tests that changing a concrete field into a ManyToManyField
  1505. first removes the concrete field and then adds the m2m field.
  1506. """
  1507. before = self.make_project_state([self.author_with_former_m2m])
  1508. after = self.make_project_state([self.author_with_m2m, self.publisher])
  1509. autodetector = MigrationAutodetector(before, after)
  1510. changes = autodetector._detect_changes()
  1511. # Right number/type of migrations?
  1512. self.assertNumberMigrations(changes, "testapp", 1)
  1513. self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "RemoveField", "AddField"])
  1514. self.assertOperationAttributes(changes, 'testapp', 0, 0, name='Publisher')
  1515. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publishers", model_name='author')
  1516. self.assertOperationAttributes(changes, 'testapp', 0, 2, name="publishers", model_name='author')
  1517. def test_many_to_many_changed_to_concrete_field(self):
  1518. """
  1519. #23938 - Tests that changing a ManyToManyField into a concrete field
  1520. first removes the m2m field and then adds the concrete field.
  1521. """
  1522. before = self.make_project_state([self.author_with_m2m, self.publisher])
  1523. after = self.make_project_state([self.author_with_former_m2m])
  1524. autodetector = MigrationAutodetector(before, after)
  1525. changes = autodetector._detect_changes()
  1526. # Right number/type of migrations?
  1527. self.assertNumberMigrations(changes, "testapp", 1)
  1528. self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "AddField", "DeleteModel"])
  1529. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers", model_name='author')
  1530. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publishers", model_name='author')
  1531. self.assertOperationAttributes(changes, 'testapp', 0, 2, name='Publisher')
  1532. self.assertOperationFieldAttributes(changes, 'testapp', 0, 1, max_length=100)
  1533. def test_non_circular_foreignkey_dependency_removal(self):
  1534. """
  1535. If two models with a ForeignKey from one to the other are removed at the
  1536. same time, the autodetector should remove them in the correct order.
  1537. """
  1538. before = self.make_project_state([self.author_with_publisher, self.publisher_with_author])
  1539. after = self.make_project_state([])
  1540. autodetector = MigrationAutodetector(before, after)
  1541. changes = autodetector._detect_changes()
  1542. # Right number/type of migrations?
  1543. self.assertNumberMigrations(changes, "testapp", 1)
  1544. self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "RemoveField", "DeleteModel", "DeleteModel"])
  1545. self.assertOperationAttributes(changes, "testapp", 0, 0, name="publisher", model_name='author')
  1546. self.assertOperationAttributes(changes, "testapp", 0, 1, name="author", model_name='publisher')
  1547. self.assertOperationAttributes(changes, "testapp", 0, 2, name="Author")
  1548. self.assertOperationAttributes(changes, "testapp", 0, 3, name="Publisher")
  1549. def test_alter_model_options(self):
  1550. """Changing a model's options should make a change."""
  1551. before = self.make_project_state([self.author_empty])
  1552. after = self.make_project_state([self.author_with_options])
  1553. autodetector = MigrationAutodetector(before, after)
  1554. changes = autodetector._detect_changes()
  1555. # Right number/type of migrations?
  1556. self.assertNumberMigrations(changes, "testapp", 1)
  1557. self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"])
  1558. self.assertOperationAttributes(changes, "testapp", 0, 0, options={
  1559. "permissions": [('can_hire', 'Can hire')],
  1560. "verbose_name": "Authi",
  1561. })
  1562. # Changing them back to empty should also make a change
  1563. before = self.make_project_state([self.author_with_options])
  1564. after = self.make_project_state([self.author_empty])
  1565. autodetector = MigrationAutodetector(before, after)
  1566. changes = autodetector._detect_changes()
  1567. # Right number/type of migrations?
  1568. self.assertNumberMigrations(changes, "testapp", 1)
  1569. self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"])
  1570. self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", options={})
  1571. def test_alter_model_options_proxy(self):
  1572. """Changing a proxy model's options should also make a change."""
  1573. before = self.make_project_state([self.author_proxy, self.author_empty])
  1574. after = self.make_project_state([self.author_proxy_options, self.author_empty])
  1575. autodetector = MigrationAutodetector(before, after)
  1576. changes = autodetector._detect_changes()
  1577. # Right number/type of migrations?
  1578. self.assertNumberMigrations(changes, "testapp", 1)
  1579. self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"])
  1580. self.assertOperationAttributes(changes, "testapp", 0, 0, name="authorproxy", options={
  1581. "verbose_name": "Super Author"
  1582. })
  1583. def test_set_alter_order_with_respect_to(self):
  1584. """Tests that setting order_with_respect_to adds a field."""
  1585. # Make state
  1586. before = self.make_project_state([self.book, self.author_with_book])
  1587. after = self.make_project_state([self.book, self.author_with_book_order_wrt])
  1588. autodetector = MigrationAutodetector(before, after)
  1589. changes = autodetector._detect_changes()
  1590. # Right number/type of migrations?
  1591. self.assertNumberMigrations(changes, 'testapp', 1)
  1592. self.assertOperationTypes(changes, 'testapp', 0, ["AlterOrderWithRespectTo"])
  1593. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="author", order_with_respect_to="book")
  1594. def test_add_alter_order_with_respect_to(self):
  1595. """
  1596. Tests that setting order_with_respect_to when adding the FK too does
  1597. things in the right order.
  1598. """
  1599. # Make state
  1600. before = self.make_project_state([self.author_name])
  1601. after = self.make_project_state([self.book, self.author_with_book_order_wrt])
  1602. autodetector = MigrationAutodetector(before, after)
  1603. changes = autodetector._detect_changes()
  1604. # Right number/type of migrations?
  1605. self.assertNumberMigrations(changes, 'testapp', 1)
  1606. self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AlterOrderWithRespectTo"])
  1607. self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name="book")
  1608. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author", order_with_respect_to="book")
  1609. def test_remove_alter_order_with_respect_to(self):
  1610. """
  1611. Tests that removing order_with_respect_to when removing the FK too does
  1612. things in the right order.
  1613. """
  1614. # Make state
  1615. before = self.make_project_state([self.book, self.author_with_book_order_wrt])
  1616. after = self.make_project_state([self.author_name])
  1617. autodetector = MigrationAutodetector(before, after)
  1618. changes = autodetector._detect_changes()
  1619. # Right number/type of migrations?
  1620. self.assertNumberMigrations(changes, 'testapp', 1)
  1621. self.assertOperationTypes(changes, 'testapp', 0, ["AlterOrderWithRespectTo", "RemoveField"])
  1622. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="author", order_with_respect_to=None)
  1623. self.assertOperationAttributes(changes, 'testapp', 0, 1, model_name="author", name="book")
  1624. def test_add_model_order_with_respect_to(self):
  1625. """
  1626. Tests that setting order_with_respect_to when adding the whole model
  1627. does things in the right order.
  1628. """
  1629. # Make state
  1630. before = self.make_project_state([])
  1631. after = self.make_project_state([self.book, self.author_with_book_order_wrt])
  1632. autodetector = MigrationAutodetector(before, after)
  1633. changes = autodetector._detect_changes()
  1634. # Right number/type of migrations?
  1635. self.assertNumberMigrations(changes, 'testapp', 1)
  1636. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "AlterOrderWithRespectTo"])
  1637. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author", order_with_respect_to="book")
  1638. self.assertNotIn("_order", [name for name, field in changes['testapp'][0].operations[0].fields])
  1639. def test_alter_model_managers(self):
  1640. """
  1641. Tests that changing the model managers adds a new operation.
  1642. """
  1643. # Make state
  1644. before = self.make_project_state([self.other_pony])
  1645. after = self.make_project_state([self.other_pony_food])
  1646. autodetector = MigrationAutodetector(before, after)
  1647. changes = autodetector._detect_changes()
  1648. # Right number/type of migrations?
  1649. self.assertNumberMigrations(changes, 'otherapp', 1)
  1650. self.assertOperationTypes(changes, 'otherapp', 0, ["AlterModelManagers"])
  1651. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="pony")
  1652. self.assertEqual([name for name, mgr in changes['otherapp'][0].operations[0].managers],
  1653. ['food_qs', 'food_mgr', 'food_mgr_kwargs'])
  1654. self.assertEqual(changes['otherapp'][0].operations[0].managers[1][1].args, ('a', 'b', 1, 2))
  1655. self.assertEqual(changes['otherapp'][0].operations[0].managers[2][1].args, ('x', 'y', 3, 4))
  1656. def test_swappable_first_inheritance(self):
  1657. """Tests that swappable models get their CreateModel first."""
  1658. # Make state
  1659. before = self.make_project_state([])
  1660. after = self.make_project_state([self.custom_user, self.aardvark])
  1661. autodetector = MigrationAutodetector(before, after)
  1662. changes = autodetector._detect_changes()
  1663. # Right number/type of migrations?
  1664. self.assertNumberMigrations(changes, 'thirdapp', 1)
  1665. self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel", "CreateModel"])
  1666. self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="CustomUser")
  1667. self.assertOperationAttributes(changes, 'thirdapp', 0, 1, name="Aardvark")
  1668. @override_settings(AUTH_USER_MODEL="thirdapp.CustomUser")
  1669. def test_swappable_first_setting(self):
  1670. """Tests that swappable models get their CreateModel first."""
  1671. # Make state
  1672. before = self.make_project_state([])
  1673. after = self.make_project_state([self.custom_user_no_inherit, self.aardvark])
  1674. autodetector = MigrationAutodetector(before, after)
  1675. changes = autodetector._detect_changes()
  1676. # Right number/type of migrations?
  1677. self.assertNumberMigrations(changes, 'thirdapp', 1)
  1678. self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel", "CreateModel"])
  1679. self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="CustomUser")
  1680. self.assertOperationAttributes(changes, 'thirdapp', 0, 1, name="Aardvark")
  1681. def test_bases_first(self):
  1682. """Tests that bases of other models come first."""
  1683. # Make state
  1684. before = self.make_project_state([])
  1685. after = self.make_project_state([self.aardvark_based_on_author, self.author_name])
  1686. autodetector = MigrationAutodetector(before, after)
  1687. changes = autodetector._detect_changes()
  1688. # Right number/type of migrations?
  1689. self.assertNumberMigrations(changes, 'testapp', 1)
  1690. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"])
  1691. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  1692. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Aardvark")
  1693. def test_multiple_bases(self):
  1694. """#23956 - Tests that inheriting models doesn't move *_ptr fields into AddField operations."""
  1695. A = ModelState("app", "A", [("a_id", models.AutoField(primary_key=True))])
  1696. B = ModelState("app", "B", [("b_id", models.AutoField(primary_key=True))])
  1697. C = ModelState("app", "C", [], bases=("app.A", "app.B"))
  1698. D = ModelState("app", "D", [], bases=("app.A", "app.B"))
  1699. E = ModelState("app", "E", [], bases=("app.A", "app.B"))
  1700. # Make state
  1701. before = self.make_project_state([])
  1702. after = self.make_project_state([A, B, C, D, E])
  1703. autodetector = MigrationAutodetector(before, after)
  1704. changes = autodetector._detect_changes()
  1705. # Right number/type of migrations?
  1706. self.assertNumberMigrations(changes, "app", 1)
  1707. self.assertOperationTypes(changes, "app", 0, [
  1708. "CreateModel", "CreateModel", "CreateModel", "CreateModel", "CreateModel"
  1709. ])
  1710. self.assertOperationAttributes(changes, "app", 0, 0, name="A")
  1711. self.assertOperationAttributes(changes, "app", 0, 1, name="B")
  1712. self.assertOperationAttributes(changes, "app", 0, 2, name="C")
  1713. self.assertOperationAttributes(changes, "app", 0, 3, name="D")
  1714. self.assertOperationAttributes(changes, "app", 0, 4, name="E")
  1715. def test_proxy_bases_first(self):
  1716. """Tests that bases of proxies come first."""
  1717. # Make state
  1718. before = self.make_project_state([])
  1719. after = self.make_project_state([self.author_empty, self.author_proxy, self.author_proxy_proxy])
  1720. autodetector = MigrationAutodetector(before, after)
  1721. changes = autodetector._detect_changes()
  1722. # Right number/type of migrations?
  1723. self.assertNumberMigrations(changes, 'testapp', 1)
  1724. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel", "CreateModel"])
  1725. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  1726. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="AuthorProxy")
  1727. self.assertOperationAttributes(changes, 'testapp', 0, 2, name="AAuthorProxyProxy")
  1728. def test_pk_fk_included(self):
  1729. """
  1730. Tests that a relation used as the primary key is kept as part of
  1731. CreateModel.
  1732. """
  1733. # Make state
  1734. before = self.make_project_state([])
  1735. after = self.make_project_state([self.aardvark_pk_fk_author, self.author_name])
  1736. autodetector = MigrationAutodetector(before, after)
  1737. changes = autodetector._detect_changes()
  1738. # Right number/type of migrations?
  1739. self.assertNumberMigrations(changes, 'testapp', 1)
  1740. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"])
  1741. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author")
  1742. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Aardvark")
  1743. def test_first_dependency(self):
  1744. """
  1745. Tests that a dependency to an app with no migrations uses __first__.
  1746. """
  1747. # Load graph
  1748. loader = MigrationLoader(connection)
  1749. # Make state
  1750. before = self.make_project_state([])
  1751. after = self.make_project_state([self.book_migrations_fk])
  1752. after.real_apps = ["migrations"]
  1753. autodetector = MigrationAutodetector(before, after)
  1754. changes = autodetector._detect_changes(graph=loader.graph)
  1755. # Right number/type of migrations?
  1756. self.assertNumberMigrations(changes, 'otherapp', 1)
  1757. self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"])
  1758. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book")
  1759. self.assertMigrationDependencies(changes, 'otherapp', 0, [("migrations", "__first__")])
  1760. @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
  1761. def test_last_dependency(self):
  1762. """
  1763. Tests that a dependency to an app with existing migrations uses the
  1764. last migration of that app.
  1765. """
  1766. # Load graph
  1767. loader = MigrationLoader(connection)
  1768. # Make state
  1769. before = self.make_project_state([])
  1770. after = self.make_project_state([self.book_migrations_fk])
  1771. after.real_apps = ["migrations"]
  1772. autodetector = MigrationAutodetector(before, after)
  1773. changes = autodetector._detect_changes(graph=loader.graph)
  1774. # Right number/type of migrations?
  1775. self.assertNumberMigrations(changes, 'otherapp', 1)
  1776. self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"])
  1777. self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book")
  1778. self.assertMigrationDependencies(changes, 'otherapp', 0, [("migrations", "0002_second")])
  1779. def test_alter_fk_before_model_deletion(self):
  1780. """
  1781. Tests that ForeignKeys are altered _before_ the model they used to
  1782. refer to are deleted.
  1783. """
  1784. # Make state
  1785. before = self.make_project_state([self.author_name, self.publisher_with_author])
  1786. after = self.make_project_state([self.aardvark_testapp, self.publisher_with_aardvark_author])
  1787. autodetector = MigrationAutodetector(before, after)
  1788. changes = autodetector._detect_changes()
  1789. # Right number/type of migrations?
  1790. self.assertNumberMigrations(changes, 'testapp', 1)
  1791. self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "AlterField", "DeleteModel"])
  1792. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Aardvark")
  1793. self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author")
  1794. self.assertOperationAttributes(changes, 'testapp', 0, 2, name="Author")
  1795. def test_fk_dependency_other_app(self):
  1796. """
  1797. #23100 - Tests that ForeignKeys correctly depend on other apps' models.
  1798. """
  1799. # Make state
  1800. before = self.make_project_state([self.author_name, self.book])
  1801. after = self.make_project_state([self.author_with_book, self.book])
  1802. autodetector = MigrationAutodetector(before, after)
  1803. changes = autodetector._detect_changes()
  1804. # Right number/type of migrations?
  1805. self.assertNumberMigrations(changes, 'testapp', 1)
  1806. self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
  1807. self.assertOperationAttributes(changes, 'testapp', 0, 0, name="book")
  1808. self.assertMigrationDependencies(changes, 'testapp', 0, [("otherapp", "__first__")])
  1809. def test_circular_dependency_mixed_addcreate(self):
  1810. """
  1811. #23315 - Tests that the dependency resolver knows to put all CreateModel
  1812. before AddField and not become unsolvable.
  1813. """
  1814. address = ModelState("a", "Address", [
  1815. ("id", models.AutoField(primary_key=True)),
  1816. ("country", models.ForeignKey("b.DeliveryCountry")),
  1817. ])
  1818. person = ModelState("a", "Person", [
  1819. ("id", models.AutoField(primary_key=True)),
  1820. ])
  1821. apackage = ModelState("b", "APackage", [
  1822. ("id", models.AutoField(primary_key=True)),
  1823. ("person", models.ForeignKey("a.Person")),
  1824. ])
  1825. country = ModelState("b", "DeliveryCountry", [
  1826. ("id", models.AutoField(primary_key=True)),
  1827. ])
  1828. # Make state
  1829. before = self.make_project_state([])
  1830. after = self.make_project_state([address, person, apackage, country])
  1831. autodetector = MigrationAutodetector(before, after)
  1832. changes = autodetector._detect_changes()
  1833. # Right number/type of migrations?
  1834. self.assertNumberMigrations(changes, 'a', 2)
  1835. self.assertNumberMigrations(changes, 'b', 1)
  1836. self.assertOperationTypes(changes, 'a', 0, ["CreateModel", "CreateModel"])
  1837. self.assertOperationTypes(changes, 'a', 1, ["AddField"])
  1838. self.assertOperationTypes(changes, 'b', 0, ["CreateModel", "CreateModel"])
  1839. @override_settings(AUTH_USER_MODEL="a.Tenant")
  1840. def test_circular_dependency_swappable(self):
  1841. """
  1842. #23322 - Tests that the dependency resolver knows to explicitly resolve
  1843. swappable models.
  1844. """
  1845. tenant = ModelState("a", "Tenant", [
  1846. ("id", models.AutoField(primary_key=True)),
  1847. ("primary_address", models.ForeignKey("b.Address"))],
  1848. bases=(AbstractBaseUser, )
  1849. )
  1850. address = ModelState("b", "Address", [
  1851. ("id", models.AutoField(primary_key=True)),
  1852. ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL)),
  1853. ])
  1854. # Make state
  1855. before = self.make_project_state([])
  1856. after = self.make_project_state([address, tenant])
  1857. autodetector = MigrationAutodetector(before, after)
  1858. changes = autodetector._detect_changes()
  1859. # Right number/type of migrations?
  1860. self.assertNumberMigrations(changes, 'a', 2)
  1861. self.assertOperationTypes(changes, 'a', 0, ["CreateModel"])
  1862. self.assertOperationTypes(changes, 'a', 1, ["AddField"])
  1863. self.assertMigrationDependencies(changes, 'a', 0, [])
  1864. self.assertMigrationDependencies(changes, 'a', 1, [('a', 'auto_1'), ('b', 'auto_1')])
  1865. # Right number/type of migrations?
  1866. self.assertNumberMigrations(changes, 'b', 1)
  1867. self.assertOperationTypes(changes, 'b', 0, ["CreateModel"])
  1868. self.assertMigrationDependencies(changes, 'b', 0, [('__setting__', 'AUTH_USER_MODEL')])
  1869. @override_settings(AUTH_USER_MODEL="b.Tenant")
  1870. def test_circular_dependency_swappable2(self):
  1871. """
  1872. #23322 - Tests that the dependency resolver knows to explicitly resolve
  1873. swappable models but with the swappable not being the first migrated
  1874. model.
  1875. """
  1876. address = ModelState("a", "Address", [
  1877. ("id", models.AutoField(primary_key=True)),
  1878. ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL)),
  1879. ])
  1880. tenant = ModelState("b", "Tenant", [
  1881. ("id", models.AutoField(primary_key=True)),
  1882. ("primary_address", models.ForeignKey("a.Address"))],
  1883. bases=(AbstractBaseUser, )
  1884. )
  1885. # Make state
  1886. before = self.make_project_state([])
  1887. after = self.make_project_state([address, tenant])
  1888. autodetector = MigrationAutodetector(before, after)
  1889. changes = autodetector._detect_changes()
  1890. # Right number/type of migrations?
  1891. self.assertNumberMigrations(changes, 'a', 2)
  1892. self.assertOperationTypes(changes, 'a', 0, ["CreateModel"])
  1893. self.assertOperationTypes(changes, 'a', 1, ["AddField"])
  1894. self.assertMigrationDependencies(changes, 'a', 0, [])
  1895. self.assertMigrationDependencies(changes, 'a', 1, [('__setting__', 'AUTH_USER_MODEL'), ('a', 'auto_1')])
  1896. # Right number/type of migrations?
  1897. self.assertNumberMigrations(changes, 'b', 1)
  1898. self.assertOperationTypes(changes, 'b', 0, ["CreateModel"])
  1899. self.assertMigrationDependencies(changes, 'b', 0, [('a', 'auto_1')])
  1900. @override_settings(AUTH_USER_MODEL="a.Person")
  1901. def test_circular_dependency_swappable_self(self):
  1902. """
  1903. #23322 - Tests that the dependency resolver knows to explicitly resolve
  1904. swappable models.
  1905. """
  1906. person = ModelState("a", "Person", [
  1907. ("id", models.AutoField(primary_key=True)),
  1908. ("parent1", models.ForeignKey(settings.AUTH_USER_MODEL, related_name='children'))
  1909. ])
  1910. # Make state
  1911. before = self.make_project_state([])
  1912. after = self.make_project_state([person])
  1913. autodetector = MigrationAutodetector(before, after)
  1914. changes = autodetector._detect_changes()
  1915. # Right number/type of migrations?
  1916. self.assertNumberMigrations(changes, 'a', 1)
  1917. self.assertOperationTypes(changes, 'a', 0, ["CreateModel"])
  1918. self.assertMigrationDependencies(changes, 'a', 0, [])
  1919. @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition',
  1920. side_effect=AssertionError("Should not have prompted for not null addition"))
  1921. def test_add_blank_textfield_and_charfield(self, mocked_ask_method):
  1922. """
  1923. #23405 - Adding a NOT NULL and blank `CharField` or `TextField`
  1924. without default should not prompt for a default.
  1925. """
  1926. before = self.make_project_state([self.author_empty])
  1927. after = self.make_project_state([self.author_with_biography_blank])
  1928. autodetector = MigrationAutodetector(before, after)
  1929. changes = autodetector._detect_changes()
  1930. # Right number/type of migrations?
  1931. self.assertNumberMigrations(changes, 'testapp', 1)
  1932. self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField"])
  1933. self.assertOperationAttributes(changes, 'testapp', 0, 0)
  1934. @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition')
  1935. def test_add_non_blank_textfield_and_charfield(self, mocked_ask_method):
  1936. """
  1937. #23405 - Adding a NOT NULL and non-blank `CharField` or `TextField`
  1938. without default should prompt for a default.
  1939. """
  1940. before = self.make_project_state([self.author_empty])
  1941. after = self.make_project_state([self.author_with_biography_non_blank])
  1942. autodetector = MigrationAutodetector(before, after)
  1943. changes = autodetector._detect_changes()
  1944. self.assertEqual(mocked_ask_method.call_count, 2)
  1945. # Right number/type of migrations?
  1946. self.assertNumberMigrations(changes, 'testapp', 1)
  1947. self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField"])
  1948. self.assertOperationAttributes(changes, 'testapp', 0, 0)