models.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. from __future__ import unicode_literals
  2. from django.db import models
  3. from django.db.migrations.operations.base import Operation
  4. from django.db.migrations.state import ModelState
  5. from django.db.models.options import normalize_together
  6. from django.utils import six
  7. from django.utils.functional import cached_property
  8. from .fields import (
  9. AddField, AlterField, FieldOperation, RemoveField, RenameField,
  10. )
  11. class ModelOperation(Operation):
  12. def __init__(self, name):
  13. self.name = name
  14. @cached_property
  15. def name_lower(self):
  16. return self.name.lower()
  17. def reduce(self, operation, in_between, app_label=None):
  18. return (
  19. super(ModelOperation, self).reduce(operation, in_between, app_label=app_label) or
  20. not operation.references_model(self.name, app_label)
  21. )
  22. class CreateModel(ModelOperation):
  23. """
  24. Create a model's table.
  25. """
  26. serialization_expand_args = ['fields', 'options', 'managers']
  27. def __init__(self, name, fields, options=None, bases=None, managers=None):
  28. self.fields = fields
  29. self.options = options or {}
  30. self.bases = bases or (models.Model,)
  31. self.managers = managers or []
  32. super(CreateModel, self).__init__(name)
  33. def deconstruct(self):
  34. kwargs = {
  35. 'name': self.name,
  36. 'fields': self.fields,
  37. }
  38. if self.options:
  39. kwargs['options'] = self.options
  40. if self.bases and self.bases != (models.Model,):
  41. kwargs['bases'] = self.bases
  42. if self.managers and self.managers != [('objects', models.Manager())]:
  43. kwargs['managers'] = self.managers
  44. return (
  45. self.__class__.__name__,
  46. [],
  47. kwargs
  48. )
  49. def state_forwards(self, app_label, state):
  50. state.add_model(ModelState(
  51. app_label,
  52. self.name,
  53. list(self.fields),
  54. dict(self.options),
  55. tuple(self.bases),
  56. list(self.managers),
  57. ))
  58. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  59. model = to_state.apps.get_model(app_label, self.name)
  60. if self.allow_migrate_model(schema_editor.connection.alias, model):
  61. schema_editor.create_model(model)
  62. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  63. model = from_state.apps.get_model(app_label, self.name)
  64. if self.allow_migrate_model(schema_editor.connection.alias, model):
  65. schema_editor.delete_model(model)
  66. def describe(self):
  67. return "Create %smodel %s" % ("proxy " if self.options.get("proxy", False) else "", self.name)
  68. def references_model(self, name, app_label=None):
  69. strings_to_check = [self.name]
  70. # Check we didn't inherit from the model
  71. for base in self.bases:
  72. if isinstance(base, six.string_types):
  73. strings_to_check.append(base.split(".")[-1])
  74. # Check we have no FKs/M2Ms with it
  75. for fname, field in self.fields:
  76. if field.remote_field:
  77. if isinstance(field.remote_field.model, six.string_types):
  78. strings_to_check.append(field.remote_field.model.split(".")[-1])
  79. # Now go over all the strings and compare them
  80. for string in strings_to_check:
  81. if string.lower() == name.lower():
  82. return True
  83. return False
  84. def model_to_key(self, model):
  85. """
  86. Take either a model class or an "app_label.ModelName" string
  87. and return (app_label, object_name).
  88. """
  89. if isinstance(model, six.string_types):
  90. return model.split(".", 1)
  91. else:
  92. return model._meta.app_label, model._meta.object_name
  93. def reduce(self, operation, in_between, app_label=None):
  94. if (isinstance(operation, DeleteModel) and
  95. self.name_lower == operation.name_lower and
  96. not self.options.get("proxy", False)):
  97. return []
  98. elif isinstance(operation, RenameModel) and self.name_lower == operation.old_name_lower:
  99. return [
  100. CreateModel(
  101. operation.new_name,
  102. fields=self.fields,
  103. options=self.options,
  104. bases=self.bases,
  105. managers=self.managers,
  106. ),
  107. ]
  108. elif isinstance(operation, FieldOperation) and self.name_lower == operation.model_name_lower:
  109. if isinstance(operation, AddField):
  110. # Don't allow optimizations of FKs through models they reference
  111. if hasattr(operation.field, "remote_field") and operation.field.remote_field:
  112. for between in in_between:
  113. # Check that it doesn't point to the model
  114. app_label, object_name = self.model_to_key(operation.field.remote_field.model)
  115. if between.references_model(object_name, app_label):
  116. return False
  117. # Check that it's not through the model
  118. if getattr(operation.field.remote_field, "through", None):
  119. app_label, object_name = self.model_to_key(operation.field.remote_field.through)
  120. if between.references_model(object_name, app_label):
  121. return False
  122. return [
  123. CreateModel(
  124. self.name,
  125. fields=self.fields + [(operation.name, operation.field)],
  126. options=self.options,
  127. bases=self.bases,
  128. managers=self.managers,
  129. ),
  130. ]
  131. elif isinstance(operation, AlterField):
  132. return [
  133. CreateModel(
  134. self.name,
  135. fields=[
  136. (n, operation.field if n == operation.name else v)
  137. for n, v in self.fields
  138. ],
  139. options=self.options,
  140. bases=self.bases,
  141. managers=self.managers,
  142. ),
  143. ]
  144. elif isinstance(operation, RemoveField):
  145. return [
  146. CreateModel(
  147. self.name,
  148. fields=[
  149. (n, v)
  150. for n, v in self.fields
  151. if n.lower() != operation.name_lower
  152. ],
  153. options=self.options,
  154. bases=self.bases,
  155. managers=self.managers,
  156. ),
  157. ]
  158. elif isinstance(operation, RenameField):
  159. return [
  160. CreateModel(
  161. self.name,
  162. fields=[
  163. (operation.new_name if n == operation.old_name else n, v)
  164. for n, v in self.fields
  165. ],
  166. options=self.options,
  167. bases=self.bases,
  168. managers=self.managers,
  169. ),
  170. ]
  171. return super(CreateModel, self).reduce(operation, in_between, app_label=app_label)
  172. class DeleteModel(ModelOperation):
  173. """
  174. Drops a model's table.
  175. """
  176. def deconstruct(self):
  177. kwargs = {
  178. 'name': self.name,
  179. }
  180. return (
  181. self.__class__.__name__,
  182. [],
  183. kwargs
  184. )
  185. def state_forwards(self, app_label, state):
  186. state.remove_model(app_label, self.name_lower)
  187. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  188. model = from_state.apps.get_model(app_label, self.name)
  189. if self.allow_migrate_model(schema_editor.connection.alias, model):
  190. schema_editor.delete_model(model)
  191. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  192. model = to_state.apps.get_model(app_label, self.name)
  193. if self.allow_migrate_model(schema_editor.connection.alias, model):
  194. schema_editor.create_model(model)
  195. def references_model(self, name, app_label=None):
  196. return name.lower() == self.name_lower
  197. def describe(self):
  198. return "Delete model %s" % (self.name, )
  199. class RenameModel(ModelOperation):
  200. """
  201. Renames a model.
  202. """
  203. def __init__(self, old_name, new_name):
  204. self.old_name = old_name
  205. self.new_name = new_name
  206. super(RenameModel, self).__init__(old_name)
  207. @cached_property
  208. def old_name_lower(self):
  209. return self.old_name.lower()
  210. @cached_property
  211. def new_name_lower(self):
  212. return self.new_name.lower()
  213. def deconstruct(self):
  214. kwargs = {
  215. 'old_name': self.old_name,
  216. 'new_name': self.new_name,
  217. }
  218. return (
  219. self.__class__.__name__,
  220. [],
  221. kwargs
  222. )
  223. def state_forwards(self, app_label, state):
  224. apps = state.apps
  225. model = apps.get_model(app_label, self.old_name)
  226. model._meta.apps = apps
  227. # Get all of the related objects we need to repoint
  228. all_related_objects = (
  229. f for f in model._meta.get_fields(include_hidden=True)
  230. if f.auto_created and not f.concrete and (not f.hidden or f.many_to_many)
  231. )
  232. # Rename the model
  233. state.models[app_label, self.new_name_lower] = state.models[app_label, self.old_name_lower]
  234. state.models[app_label, self.new_name_lower].name = self.new_name
  235. state.remove_model(app_label, self.old_name_lower)
  236. # Repoint the FKs and M2Ms pointing to us
  237. for related_object in all_related_objects:
  238. if related_object.model is not model:
  239. # The model being renamed does not participate in this relation
  240. # directly. Rather, a superclass does.
  241. continue
  242. # Use the new related key for self referential related objects.
  243. if related_object.related_model == model:
  244. related_key = (app_label, self.new_name_lower)
  245. else:
  246. related_key = (
  247. related_object.related_model._meta.app_label,
  248. related_object.related_model._meta.model_name,
  249. )
  250. new_fields = []
  251. for name, field in state.models[related_key].fields:
  252. if name == related_object.field.name:
  253. field = field.clone()
  254. field.remote_field.model = "%s.%s" % (app_label, self.new_name)
  255. new_fields.append((name, field))
  256. state.models[related_key].fields = new_fields
  257. state.reload_model(*related_key)
  258. state.reload_model(app_label, self.new_name_lower)
  259. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  260. new_model = to_state.apps.get_model(app_label, self.new_name)
  261. if self.allow_migrate_model(schema_editor.connection.alias, new_model):
  262. old_model = from_state.apps.get_model(app_label, self.old_name)
  263. # Move the main table
  264. schema_editor.alter_db_table(
  265. new_model,
  266. old_model._meta.db_table,
  267. new_model._meta.db_table,
  268. )
  269. # Alter the fields pointing to us
  270. for related_object in old_model._meta.related_objects:
  271. if related_object.related_model == old_model:
  272. model = new_model
  273. related_key = (app_label, self.new_name_lower)
  274. else:
  275. model = related_object.related_model
  276. related_key = (
  277. related_object.related_model._meta.app_label,
  278. related_object.related_model._meta.model_name,
  279. )
  280. to_field = to_state.apps.get_model(
  281. *related_key
  282. )._meta.get_field(related_object.field.name)
  283. schema_editor.alter_field(
  284. model,
  285. related_object.field,
  286. to_field,
  287. )
  288. # Rename M2M fields whose name is based on this model's name.
  289. fields = zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many)
  290. for (old_field, new_field) in fields:
  291. # Skip self-referential fields as these are renamed above.
  292. if new_field.model == new_field.related_model or not new_field.remote_field.through._meta.auto_created:
  293. continue
  294. # Rename the M2M table that's based on this model's name.
  295. old_m2m_model = old_field.remote_field.through
  296. new_m2m_model = new_field.remote_field.through
  297. schema_editor.alter_db_table(
  298. new_m2m_model,
  299. old_m2m_model._meta.db_table,
  300. new_m2m_model._meta.db_table,
  301. )
  302. # Rename the column in the M2M table that's based on this
  303. # model's name.
  304. schema_editor.alter_field(
  305. new_m2m_model,
  306. old_m2m_model._meta.get_field(old_model._meta.model_name),
  307. new_m2m_model._meta.get_field(new_model._meta.model_name),
  308. )
  309. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  310. self.new_name_lower, self.old_name_lower = self.old_name_lower, self.new_name_lower
  311. self.new_name, self.old_name = self.old_name, self.new_name
  312. self.database_forwards(app_label, schema_editor, from_state, to_state)
  313. self.new_name_lower, self.old_name_lower = self.old_name_lower, self.new_name_lower
  314. self.new_name, self.old_name = self.old_name, self.new_name
  315. def references_model(self, name, app_label=None):
  316. return (
  317. name.lower() == self.old_name_lower or
  318. name.lower() == self.new_name_lower
  319. )
  320. def describe(self):
  321. return "Rename model %s to %s" % (self.old_name, self.new_name)
  322. def reduce(self, operation, in_between, app_label=None):
  323. if (isinstance(operation, RenameModel) and
  324. self.new_name_lower == operation.old_name_lower):
  325. return [
  326. RenameModel(
  327. self.old_name,
  328. operation.new_name,
  329. ),
  330. ]
  331. # Skip `ModelOperation.reduce` as we want to run `references_model`
  332. # against self.new_name.
  333. return (
  334. super(ModelOperation, self).reduce(operation, in_between, app_label=app_label) or
  335. not operation.references_model(self.new_name, app_label)
  336. )
  337. class AlterModelTable(ModelOperation):
  338. """
  339. Renames a model's table
  340. """
  341. def __init__(self, name, table):
  342. self.table = table
  343. super(AlterModelTable, self).__init__(name)
  344. def deconstruct(self):
  345. kwargs = {
  346. 'name': self.name,
  347. 'table': self.table,
  348. }
  349. return (
  350. self.__class__.__name__,
  351. [],
  352. kwargs
  353. )
  354. def state_forwards(self, app_label, state):
  355. state.models[app_label, self.name_lower].options["db_table"] = self.table
  356. state.reload_model(app_label, self.name_lower)
  357. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  358. new_model = to_state.apps.get_model(app_label, self.name)
  359. if self.allow_migrate_model(schema_editor.connection.alias, new_model):
  360. old_model = from_state.apps.get_model(app_label, self.name)
  361. schema_editor.alter_db_table(
  362. new_model,
  363. old_model._meta.db_table,
  364. new_model._meta.db_table,
  365. )
  366. # Rename M2M fields whose name is based on this model's db_table
  367. for (old_field, new_field) in zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many):
  368. if new_field.remote_field.through._meta.auto_created:
  369. schema_editor.alter_db_table(
  370. new_field.remote_field.through,
  371. old_field.remote_field.through._meta.db_table,
  372. new_field.remote_field.through._meta.db_table,
  373. )
  374. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  375. return self.database_forwards(app_label, schema_editor, from_state, to_state)
  376. def references_model(self, name, app_label=None):
  377. return name.lower() == self.name_lower
  378. def describe(self):
  379. return "Rename table for %s to %s" % (self.name, self.table)
  380. def reduce(self, operation, in_between, app_label=None):
  381. if isinstance(operation, (AlterModelTable, DeleteModel)) and self.name_lower == operation.name_lower:
  382. return [operation]
  383. return super(AlterModelTable, self).reduce(operation, in_between, app_label=app_label)
  384. class ModelOptionOperation(ModelOperation):
  385. def reduce(self, operation, in_between, app_label=None):
  386. if isinstance(operation, (self.__class__, DeleteModel)) and self.name_lower == operation.name_lower:
  387. return [operation]
  388. return super(ModelOptionOperation, self).reduce(operation, in_between, app_label=app_label)
  389. class FieldRelatedOptionOperation(ModelOptionOperation):
  390. def reduce(self, operation, in_between, app_label=None):
  391. if (isinstance(operation, FieldOperation) and
  392. self.name_lower == operation.model_name_lower and
  393. not self.references_field(operation.model_name, operation.name)):
  394. return [operation, self]
  395. return super(FieldRelatedOptionOperation, self).reduce(operation, in_between, app_label=app_label)
  396. class AlterUniqueTogether(FieldRelatedOptionOperation):
  397. """
  398. Changes the value of unique_together to the target one.
  399. Input value of unique_together must be a set of tuples.
  400. """
  401. option_name = "unique_together"
  402. def __init__(self, name, unique_together):
  403. unique_together = normalize_together(unique_together)
  404. self.unique_together = set(tuple(cons) for cons in unique_together)
  405. super(AlterUniqueTogether, self).__init__(name)
  406. def deconstruct(self):
  407. kwargs = {
  408. 'name': self.name,
  409. 'unique_together': self.unique_together,
  410. }
  411. return (
  412. self.__class__.__name__,
  413. [],
  414. kwargs
  415. )
  416. def state_forwards(self, app_label, state):
  417. model_state = state.models[app_label, self.name_lower]
  418. model_state.options[self.option_name] = self.unique_together
  419. state.reload_model(app_label, self.name_lower)
  420. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  421. new_model = to_state.apps.get_model(app_label, self.name)
  422. if self.allow_migrate_model(schema_editor.connection.alias, new_model):
  423. old_model = from_state.apps.get_model(app_label, self.name)
  424. schema_editor.alter_unique_together(
  425. new_model,
  426. getattr(old_model._meta, self.option_name, set()),
  427. getattr(new_model._meta, self.option_name, set()),
  428. )
  429. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  430. return self.database_forwards(app_label, schema_editor, from_state, to_state)
  431. def references_model(self, name, app_label=None):
  432. return name.lower() == self.name_lower
  433. def references_field(self, model_name, name, app_label=None):
  434. return (
  435. self.references_model(model_name, app_label) and
  436. (
  437. not self.unique_together or
  438. any((name in together) for together in self.unique_together)
  439. )
  440. )
  441. def describe(self):
  442. return "Alter %s for %s (%s constraint(s))" % (self.option_name, self.name, len(self.unique_together or ''))
  443. class AlterIndexTogether(FieldRelatedOptionOperation):
  444. """
  445. Changes the value of index_together to the target one.
  446. Input value of index_together must be a set of tuples.
  447. """
  448. option_name = "index_together"
  449. def __init__(self, name, index_together):
  450. index_together = normalize_together(index_together)
  451. self.index_together = set(tuple(cons) for cons in index_together)
  452. super(AlterIndexTogether, self).__init__(name)
  453. def deconstruct(self):
  454. kwargs = {
  455. 'name': self.name,
  456. 'index_together': self.index_together,
  457. }
  458. return (
  459. self.__class__.__name__,
  460. [],
  461. kwargs
  462. )
  463. def state_forwards(self, app_label, state):
  464. model_state = state.models[app_label, self.name_lower]
  465. model_state.options[self.option_name] = self.index_together
  466. state.reload_model(app_label, self.name_lower)
  467. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  468. new_model = to_state.apps.get_model(app_label, self.name)
  469. if self.allow_migrate_model(schema_editor.connection.alias, new_model):
  470. old_model = from_state.apps.get_model(app_label, self.name)
  471. schema_editor.alter_index_together(
  472. new_model,
  473. getattr(old_model._meta, self.option_name, set()),
  474. getattr(new_model._meta, self.option_name, set()),
  475. )
  476. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  477. return self.database_forwards(app_label, schema_editor, from_state, to_state)
  478. def references_model(self, name, app_label=None):
  479. return name.lower() == self.name_lower
  480. def references_field(self, model_name, name, app_label=None):
  481. return (
  482. self.references_model(model_name, app_label) and
  483. (
  484. not self.index_together or
  485. any((name in together) for together in self.index_together)
  486. )
  487. )
  488. def describe(self):
  489. return "Alter %s for %s (%s constraint(s))" % (self.option_name, self.name, len(self.index_together or ''))
  490. class AlterOrderWithRespectTo(FieldRelatedOptionOperation):
  491. """
  492. Represents a change with the order_with_respect_to option.
  493. """
  494. def __init__(self, name, order_with_respect_to):
  495. self.order_with_respect_to = order_with_respect_to
  496. super(AlterOrderWithRespectTo, self).__init__(name)
  497. def deconstruct(self):
  498. kwargs = {
  499. 'name': self.name,
  500. 'order_with_respect_to': self.order_with_respect_to,
  501. }
  502. return (
  503. self.__class__.__name__,
  504. [],
  505. kwargs
  506. )
  507. def state_forwards(self, app_label, state):
  508. model_state = state.models[app_label, self.name_lower]
  509. model_state.options['order_with_respect_to'] = self.order_with_respect_to
  510. state.reload_model(app_label, self.name_lower)
  511. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  512. to_model = to_state.apps.get_model(app_label, self.name)
  513. if self.allow_migrate_model(schema_editor.connection.alias, to_model):
  514. from_model = from_state.apps.get_model(app_label, self.name)
  515. # Remove a field if we need to
  516. if from_model._meta.order_with_respect_to and not to_model._meta.order_with_respect_to:
  517. schema_editor.remove_field(from_model, from_model._meta.get_field("_order"))
  518. # Add a field if we need to (altering the column is untouched as
  519. # it's likely a rename)
  520. elif to_model._meta.order_with_respect_to and not from_model._meta.order_with_respect_to:
  521. field = to_model._meta.get_field("_order")
  522. if not field.has_default():
  523. field.default = 0
  524. schema_editor.add_field(
  525. from_model,
  526. field,
  527. )
  528. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  529. self.database_forwards(app_label, schema_editor, from_state, to_state)
  530. def references_model(self, name, app_label=None):
  531. return name.lower() == self.name_lower
  532. def references_field(self, model_name, name, app_label=None):
  533. return (
  534. self.references_model(model_name, app_label) and
  535. (
  536. self.order_with_respect_to is None or
  537. name == self.order_with_respect_to
  538. )
  539. )
  540. def describe(self):
  541. return "Set order_with_respect_to on %s to %s" % (self.name, self.order_with_respect_to)
  542. class AlterModelOptions(ModelOptionOperation):
  543. """
  544. Sets new model options that don't directly affect the database schema
  545. (like verbose_name, permissions, ordering). Python code in migrations
  546. may still need them.
  547. """
  548. # Model options we want to compare and preserve in an AlterModelOptions op
  549. ALTER_OPTION_KEYS = [
  550. "get_latest_by",
  551. "managed",
  552. "ordering",
  553. "permissions",
  554. "default_permissions",
  555. "select_on_save",
  556. "verbose_name",
  557. "verbose_name_plural",
  558. ]
  559. def __init__(self, name, options):
  560. self.options = options
  561. super(AlterModelOptions, self).__init__(name)
  562. def deconstruct(self):
  563. kwargs = {
  564. 'name': self.name,
  565. 'options': self.options,
  566. }
  567. return (
  568. self.__class__.__name__,
  569. [],
  570. kwargs
  571. )
  572. def state_forwards(self, app_label, state):
  573. model_state = state.models[app_label, self.name_lower]
  574. model_state.options = dict(model_state.options)
  575. model_state.options.update(self.options)
  576. for key in self.ALTER_OPTION_KEYS:
  577. if key not in self.options and key in model_state.options:
  578. del model_state.options[key]
  579. state.reload_model(app_label, self.name_lower)
  580. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  581. pass
  582. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  583. pass
  584. def references_model(self, name, app_label=None):
  585. return name.lower() == self.name_lower
  586. def describe(self):
  587. return "Change Meta options on %s" % (self.name, )
  588. class AlterModelManagers(ModelOptionOperation):
  589. """
  590. Alters the model's managers
  591. """
  592. serialization_expand_args = ['managers']
  593. def __init__(self, name, managers):
  594. self.managers = managers
  595. super(AlterModelManagers, self).__init__(name)
  596. def deconstruct(self):
  597. return (
  598. self.__class__.__name__,
  599. [self.name, self.managers],
  600. {}
  601. )
  602. def state_forwards(self, app_label, state):
  603. model_state = state.models[app_label, self.name_lower]
  604. model_state.managers = list(self.managers)
  605. state.reload_model(app_label, self.name_lower)
  606. def database_forwards(self, app_label, schema_editor, from_state, to_state):
  607. pass
  608. def database_backwards(self, app_label, schema_editor, from_state, to_state):
  609. pass
  610. def references_model(self, name, app_label=None):
  611. return name.lower() == self.name_lower
  612. def describe(self):
  613. return "Change managers on %s" % (self.name, )