debug_cursor.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. # -*- coding: utf-8 -*-
  2. import six
  3. import time
  4. import traceback
  5. from contextlib import contextmanager
  6. import django
  7. from django.conf import settings
  8. from django.core.exceptions import ImproperlyConfigured
  9. from django.db.backends import utils
  10. @contextmanager
  11. def monkey_patch_cursordebugwrapper(print_sql=None, print_sql_location=False, truncate=None, logger=six.print_, confprefix="DJANGO_EXTENSIONS"):
  12. if not print_sql:
  13. yield
  14. else:
  15. truncate = getattr(settings, '%s_PRINT_SQL_TRUNCATE' % confprefix, 1000)
  16. # Code orginally from http://gist.github.com/118990
  17. sqlparse = None
  18. if getattr(settings, '%s_SQLPARSE_ENABLED' % confprefix, True):
  19. try:
  20. import sqlparse
  21. sqlparse_format_kwargs_defaults = dict(
  22. reindent_aligned=True,
  23. truncate_strings=500,
  24. )
  25. sqlparse_format_kwargs = getattr(settings, '%s_SQLPARSE_FORMAT_KWARGS' % confprefix, sqlparse_format_kwargs_defaults)
  26. except ImportError:
  27. sqlparse = None
  28. pygments = None
  29. if getattr(settings, '%s_PYGMENTS_ENABLED' % confprefix, True):
  30. try:
  31. import pygments.lexers
  32. import pygments.formatters
  33. pygments_formatter = getattr(settings, '%s_PYGMENTS_FORMATTER' % confprefix, pygments.formatters.TerminalFormatter)
  34. pygments_formatter_kwargs = getattr(settings, '%s_PYGMENTS_FORMATTER_KWARGS' % confprefix, {})
  35. except ImportError:
  36. pass
  37. class PrintQueryWrapperMixin:
  38. def execute(self, sql, params=()):
  39. starttime = time.time()
  40. try:
  41. return utils.CursorWrapper.execute(self, sql, params)
  42. finally:
  43. execution_time = time.time() - starttime
  44. raw_sql = self.db.ops.last_executed_query(self.cursor, sql, params)
  45. if truncate:
  46. raw_sql = raw_sql[:truncate]
  47. if sqlparse:
  48. raw_sql = sqlparse.format(raw_sql, **sqlparse_format_kwargs)
  49. if pygments:
  50. raw_sql = pygments.highlight(
  51. raw_sql,
  52. pygments.lexers.get_lexer_by_name("sql"),
  53. pygments_formatter(**pygments_formatter_kwargs),
  54. )
  55. logger(raw_sql)
  56. logger("Execution time: %.6fs [Database: %s]" % (execution_time, self.db.alias))
  57. if print_sql_location:
  58. logger("Location of SQL Call:")
  59. logger(''.join(traceback.format_stack()))
  60. _CursorDebugWrapper = utils.CursorDebugWrapper
  61. class PrintCursorQueryWrapper(PrintQueryWrapperMixin, _CursorDebugWrapper):
  62. pass
  63. try:
  64. from django.db import connections
  65. _force_debug_cursor = {}
  66. for connection_name in connections:
  67. _force_debug_cursor[connection_name] = connections[connection_name].force_debug_cursor
  68. except Exception:
  69. connections = None
  70. utils.CursorDebugWrapper = PrintCursorQueryWrapper
  71. postgresql_base = None
  72. if django.VERSION >= (3, 0):
  73. try:
  74. from django.db.backends.postgresql import base as postgresql_base
  75. _PostgreSQLCursorDebugWrapper = postgresql_base.CursorDebugWrapper
  76. class PostgreSQLPrintCursorDebugWrapper(PrintQueryWrapperMixin, _PostgreSQLCursorDebugWrapper):
  77. pass
  78. except (ImproperlyConfigured, TypeError):
  79. postgresql_base = None
  80. if postgresql_base:
  81. postgresql_base.CursorDebugWrapper = PostgreSQLPrintCursorDebugWrapper
  82. if connections:
  83. for connection_name in connections:
  84. connections[connection_name].force_debug_cursor = True
  85. yield
  86. utils.CursorDebugWrapper = _CursorDebugWrapper
  87. if postgresql_base:
  88. postgresql_base.CursorDebugWrapper = _PostgreSQLCursorDebugWrapper
  89. if connections:
  90. for connection_name in connections:
  91. connections[connection_name].force_debug_cursor = _force_debug_cursor[connection_name]