reset_db.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # -*- coding: utf-8 -*-
  2. """
  3. reset_db command
  4. originally from http://www.djangosnippets.org/snippets/828/ by dnordberg
  5. """
  6. import os
  7. import logging
  8. from django.conf import settings
  9. from django.core.management.base import BaseCommand, CommandError
  10. from six.moves import input
  11. from django_extensions.settings import SQLITE_ENGINES, POSTGRESQL_ENGINES, MYSQL_ENGINES
  12. from django_extensions.management.mysql import parse_mysql_cnf
  13. from django_extensions.management.utils import signalcommand
  14. class Command(BaseCommand):
  15. help = "Resets the database for this project."
  16. def add_arguments(self, parser):
  17. super().add_arguments(parser)
  18. parser.add_argument(
  19. '--noinput', action='store_false',
  20. dest='interactive', default=True,
  21. help='Tells Django to NOT prompt the user for input of any kind.'
  22. )
  23. parser.add_argument(
  24. '--no-utf8', action='store_true', dest='no_utf8_support',
  25. default=False,
  26. help='Tells Django to not create a UTF-8 charset database'
  27. )
  28. parser.add_argument(
  29. '-U', '--user', action='store', dest='user', default=None,
  30. help='Use another user for the database than defined in settings.py'
  31. )
  32. parser.add_argument(
  33. '-O', '--owner', action='store', dest='owner', default=None,
  34. help='Use another owner for creating the database than the user defined in settings or via --user'
  35. )
  36. parser.add_argument(
  37. '-P', '--password', action='store', dest='password', default=None,
  38. help='Use another password for the database than defined in settings.py'
  39. )
  40. parser.add_argument(
  41. '-D', '--dbname', action='store', dest='dbname', default=None,
  42. help='Use another database name than defined in settings.py'
  43. )
  44. parser.add_argument(
  45. '-R', '--router', action='store', dest='router', default='default',
  46. help='Use this router-database other than defined in settings.py'
  47. )
  48. parser.add_argument(
  49. '-c', '--close-sessions', action='store_true', dest='close_sessions', default=False,
  50. help='Close database connections before dropping database (PostgreSQL only)'
  51. )
  52. @signalcommand
  53. def handle(self, *args, **options):
  54. """
  55. Reset the database for this project.
  56. Note: Transaction wrappers are in reverse as a work around for
  57. autocommit, anybody know how to do this the right way?
  58. """
  59. router = options['router']
  60. dbinfo = settings.DATABASES.get(router)
  61. if dbinfo is None:
  62. raise CommandError("Unknown database router %s" % router)
  63. engine = dbinfo.get('ENGINE')
  64. user = password = database_name = database_host = database_port = ''
  65. if engine == 'mysql':
  66. (user, password, database_name, database_host, database_port) = parse_mysql_cnf(dbinfo)
  67. user = options['user'] or dbinfo.get('USER') or user
  68. password = options['password'] or dbinfo.get('PASSWORD') or password
  69. owner = options['owner'] or user
  70. database_name = options['dbname'] or dbinfo.get('NAME') or database_name
  71. if database_name == '':
  72. raise CommandError("You need to specify DATABASE_NAME in your Django settings file.")
  73. database_host = dbinfo.get('HOST') or database_host
  74. database_port = dbinfo.get('PORT') or database_port
  75. verbosity = options["verbosity"]
  76. if options['interactive']:
  77. confirm = input("""
  78. You have requested a database reset.
  79. This will IRREVERSIBLY DESTROY
  80. ALL data in the database "%s".
  81. Are you sure you want to do this?
  82. Type 'yes' to continue, or 'no' to cancel: """ % (database_name,))
  83. else:
  84. confirm = 'yes'
  85. if confirm != 'yes':
  86. print("Reset cancelled.")
  87. return
  88. if engine in SQLITE_ENGINES:
  89. try:
  90. logging.info("Unlinking %s database", engine)
  91. os.unlink(database_name)
  92. except OSError:
  93. pass
  94. elif engine in MYSQL_ENGINES:
  95. import MySQLdb as Database
  96. kwargs = {
  97. 'user': user,
  98. 'passwd': password,
  99. }
  100. if database_host.startswith('/'):
  101. kwargs['unix_socket'] = database_host
  102. else:
  103. kwargs['host'] = database_host
  104. if database_port:
  105. kwargs['port'] = int(database_port)
  106. connection = Database.connect(**kwargs)
  107. drop_query = 'DROP DATABASE IF EXISTS `%s`' % database_name
  108. utf8_support = '' if options['no_utf8_support'] else 'CHARACTER SET utf8'
  109. create_query = 'CREATE DATABASE `%s` %s' % (database_name, utf8_support)
  110. logging.info('Executing... "%s"', drop_query)
  111. connection.query(drop_query)
  112. logging.info('Executing... "%s"', create_query)
  113. connection.query(create_query.strip())
  114. elif engine in POSTGRESQL_ENGINES:
  115. import psycopg2 as Database # NOQA
  116. conn_params = {'database': 'template1'}
  117. if user:
  118. conn_params['user'] = user
  119. if password:
  120. conn_params['password'] = password
  121. if database_host:
  122. conn_params['host'] = database_host
  123. if database_port:
  124. conn_params['port'] = database_port
  125. connection = Database.connect(**conn_params)
  126. connection.set_isolation_level(0) # autocommit false
  127. cursor = connection.cursor()
  128. if options['close_sessions']:
  129. close_sessions_query = """
  130. SELECT pg_terminate_backend(pg_stat_activity.pid)
  131. FROM pg_stat_activity
  132. WHERE pg_stat_activity.datname = '%s';
  133. """ % database_name
  134. logging.info('Executing... "%s"', close_sessions_query.strip())
  135. try:
  136. cursor.execute(close_sessions_query)
  137. except Database.ProgrammingError as e:
  138. logging.exception("Error: %s", str(e))
  139. drop_query = "DROP DATABASE \"%s\";" % database_name
  140. logging.info('Executing... "%s"', drop_query)
  141. try:
  142. cursor.execute(drop_query)
  143. except Database.ProgrammingError as e:
  144. logging.exception("Error: %s", str(e))
  145. create_query = "CREATE DATABASE \"%s\"" % database_name
  146. if owner:
  147. create_query += " WITH OWNER = \"%s\" " % owner
  148. create_query += " ENCODING = 'UTF8'"
  149. if settings.DEFAULT_TABLESPACE:
  150. create_query += ' TABLESPACE = %s;' % settings.DEFAULT_TABLESPACE
  151. else:
  152. create_query += ';'
  153. logging.info('Executing... "%s"', create_query)
  154. cursor.execute(create_query)
  155. else:
  156. raise CommandError("Unknown database engine %s" % engine)
  157. if verbosity >= 2 or options['interactive']:
  158. print("Reset successful.")