PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/django/core/management/sql.py

https://bitbucket.org/abhimskywalker/hackpack
Python | 190 lines | 132 code | 29 blank | 29 comment | 34 complexity | 5ac3417a389b0c5141ae61df7af5ff7b MD5 | raw file
  1. import os
  2. import re
  3. from django.conf import settings
  4. from django.core.management.base import CommandError
  5. from django.db import models
  6. from django.db.models import get_models
  7. def sql_create(app, style, connection):
  8. "Returns a list of the CREATE TABLE SQL statements for the given app."
  9. if connection.settings_dict['ENGINE'] == 'django.db.backends.dummy':
  10. # This must be the "dummy" database backend, which means the user
  11. # hasn't set ENGINE for the databse.
  12. raise CommandError("Django doesn't know which syntax to use for your SQL statements,\n" +
  13. "because you haven't specified the ENGINE setting for the database.\n" +
  14. "Edit your settings file and change DATBASES['default']['ENGINE'] to something like\n" +
  15. "'django.db.backends.postgresql' or 'django.db.backends.mysql'.")
  16. # Get installed models, so we generate REFERENCES right.
  17. # We trim models from the current app so that the sqlreset command does not
  18. # generate invalid SQL (leaving models out of known_models is harmless, so
  19. # we can be conservative).
  20. app_models = models.get_models(app, include_auto_created=True)
  21. final_output = []
  22. tables = connection.introspection.table_names()
  23. known_models = set([model for model in connection.introspection.installed_models(tables) if model not in app_models])
  24. pending_references = {}
  25. for model in app_models:
  26. output, references = connection.creation.sql_create_model(model, style, known_models)
  27. final_output.extend(output)
  28. for refto, refs in references.items():
  29. pending_references.setdefault(refto, []).extend(refs)
  30. if refto in known_models:
  31. final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references))
  32. final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references))
  33. # Keep track of the fact that we've created the table for this model.
  34. known_models.add(model)
  35. # Handle references to tables that are from other apps
  36. # but don't exist physically.
  37. not_installed_models = set(pending_references.keys())
  38. if not_installed_models:
  39. alter_sql = []
  40. for model in not_installed_models:
  41. alter_sql.extend(['-- ' + sql for sql in
  42. connection.creation.sql_for_pending_references(model, style, pending_references)])
  43. if alter_sql:
  44. final_output.append('-- The following references should be added but depend on non-existent tables:')
  45. final_output.extend(alter_sql)
  46. return final_output
  47. def sql_delete(app, style, connection):
  48. "Returns a list of the DROP TABLE SQL statements for the given app."
  49. # This should work even if a connection isn't available
  50. try:
  51. cursor = connection.cursor()
  52. except:
  53. cursor = None
  54. # Figure out which tables already exist
  55. if cursor:
  56. table_names = connection.introspection.get_table_list(cursor)
  57. else:
  58. table_names = []
  59. output = []
  60. # Output DROP TABLE statements for standard application tables.
  61. to_delete = set()
  62. references_to_delete = {}
  63. app_models = models.get_models(app, include_auto_created=True)
  64. for model in app_models:
  65. if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
  66. # The table exists, so it needs to be dropped
  67. opts = model._meta
  68. for f in opts.local_fields:
  69. if f.rel and f.rel.to not in to_delete:
  70. references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
  71. to_delete.add(model)
  72. for model in app_models:
  73. if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
  74. output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
  75. # Close database connection explicitly, in case this output is being piped
  76. # directly into a database client, to avoid locking issues.
  77. if cursor:
  78. cursor.close()
  79. connection.close()
  80. return output[::-1] # Reverse it, to deal with table dependencies.
  81. def sql_reset(app, style, connection):
  82. "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
  83. # This command breaks a lot and should be deprecated
  84. import warnings
  85. warnings.warn(
  86. 'This command has been deprecated. The command ``sqlflush`` can be used to delete everything. You can also use ALTER TABLE or DROP TABLE statements manually.',
  87. PendingDeprecationWarning
  88. )
  89. return sql_delete(app, style, connection) + sql_all(app, style, connection)
  90. def sql_flush(style, connection, only_django=False):
  91. """
  92. Returns a list of the SQL statements used to flush the database.
  93. If only_django is True, then only table names that have associated Django
  94. models and are in INSTALLED_APPS will be included.
  95. """
  96. if only_django:
  97. tables = connection.introspection.django_table_names(only_existing=True)
  98. else:
  99. tables = connection.introspection.table_names()
  100. statements = connection.ops.sql_flush(
  101. style, tables, connection.introspection.sequence_list()
  102. )
  103. return statements
  104. def sql_custom(app, style, connection):
  105. "Returns a list of the custom table modifying SQL statements for the given app."
  106. output = []
  107. app_models = get_models(app)
  108. app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
  109. for model in app_models:
  110. output.extend(custom_sql_for_model(model, style, connection))
  111. return output
  112. def sql_indexes(app, style, connection):
  113. "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
  114. output = []
  115. for model in models.get_models(app):
  116. output.extend(connection.creation.sql_indexes_for_model(model, style))
  117. return output
  118. def sql_all(app, style, connection):
  119. "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
  120. return sql_create(app, style, connection) + sql_custom(app, style, connection) + sql_indexes(app, style, connection)
  121. def custom_sql_for_model(model, style, connection):
  122. opts = model._meta
  123. app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
  124. output = []
  125. # Post-creation SQL should come before any initial SQL data is loaded.
  126. # However, this should not be done for models that are unmanaged or
  127. # for fields that are part of a parent model (via model inheritance).
  128. if opts.managed:
  129. post_sql_fields = [f for f in opts.local_fields if hasattr(f, 'post_create_sql')]
  130. for f in post_sql_fields:
  131. output.extend(f.post_create_sql(style, model._meta.db_table))
  132. # Some backends can't execute more than one SQL statement at a time,
  133. # so split into separate statements.
  134. statements = re.compile(r";[ \t]*$", re.M)
  135. # Find custom SQL, if it's available.
  136. backend_name = connection.settings_dict['ENGINE'].split('.')[-1]
  137. sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), backend_name)),
  138. os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
  139. for sql_file in sql_files:
  140. if os.path.exists(sql_file):
  141. fp = open(sql_file, 'U')
  142. for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
  143. # Remove any comments from the file
  144. statement = re.sub(ur"--.*([\n\Z]|$)", "", statement)
  145. if statement.strip():
  146. output.append(statement + u";")
  147. fp.close()
  148. return output
  149. def emit_post_sync_signal(created_models, verbosity, interactive, db):
  150. # Emit the post_sync signal for every application.
  151. for app in models.get_apps():
  152. app_name = app.__name__.split('.')[-2]
  153. if verbosity >= 2:
  154. print "Running post-sync handlers for application", app_name
  155. models.signals.post_syncdb.send(sender=app, app=app,
  156. created_models=created_models, verbosity=verbosity,
  157. interactive=interactive, db=db)