diff options
| -rw-r--r-- | debug_toolbar/panels/sql.py | 36 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/sql.html | 10 | ||||
| -rw-r--r-- | debug_toolbar/utils/compat/db.py | 9 | ||||
| -rw-r--r-- | debug_toolbar/utils/tracking/db.py | 24 | ||||
| -rw-r--r-- | example/example.db | bin | 55296 -> 55296 bytes | 
5 files changed, 69 insertions, 10 deletions
| diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index ba83455..344f5d6 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -1,6 +1,5 @@  import re -from django.conf import settings  from django.db.backends import BaseDatabaseWrapper  from django.template.loader import render_to_string  from django.utils.html import escape @@ -26,6 +25,36 @@ def cursor(func, self):      return CursorWrapper(result, self, logger=logger) +def get_isolation_level_display(engine, level): +    if engine == 'psycopg2': +        import psycopg2.extensions +        choices = { +            psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT: 'Autocommit', +            psycopg2.extensions.ISOLATION_LEVEL_READ_UNCOMMITTED: 'Read uncommitted', +            psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED: 'Read committed', +            psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ: 'Repeatable read', +            psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE: 'Serializable', +        } +    else: +        raise ValueError(engine) +     +    return choices.get(level) + +def get_transaction_status_display(engine, level): +    if engine == 'psycopg2': +        import psycopg2.extensions +        choices = { +            psycopg2.extensions.TRANSACTION_STATUS_IDLE: 'Idle', +            psycopg2.extensions.TRANSACTION_STATUS_ACTIVE: 'Active', +            psycopg2.extensions.TRANSACTION_STATUS_INTRANS: 'In transaction', +            psycopg2.extensions.TRANSACTION_STATUS_INERROR: 'In error', +            psycopg2.extensions.TRANSACTION_STATUS_UNKNOWN: 'Unknown', +        } +    else: +        raise ValueError(engine) +     +    return choices.get(level) +  class SQLDebugPanel(DebugPanel):      """      Panel that displays information about the SQL queries run while processing @@ -102,6 +131,10 @@ class SQLDebugPanel(DebugPanel):              for alias, query in self._queries:                  query['alias'] = alias +                if 'iso_level' in query: +                    query['iso_level'] = get_isolation_level_display(query['engine'], query['iso_level']) +                if 'trans_status' in query: +                    query['trans_status'] = get_transaction_status_display(query['engine'], query['trans_status'])                  query['sql'] = reformat_sql(query['sql'])                  query['rgb_color'] = self._databases[alias]['rgb_color']                  try: @@ -123,7 +156,6 @@ class SQLDebugPanel(DebugPanel):              'databases': sorted(self._databases.items(), key=lambda x: -x[1]['time_spent']),              'queries': [q for a, q in self._queries],              'sql_time': self._sql_time, -            'is_mysql': settings.DATABASE_ENGINE == 'mysql',          })          return render_to_string('debug_toolbar/panels/sql.html', context) diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html index bec97a4..436f3ce 100644 --- a/debug_toolbar/templates/debug_toolbar/panels/sql.html +++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html @@ -44,9 +44,9 @@  						{% if query.is_select %}  							<a class="remoteCall" href="/__debug__/sql_select/?sql={{ query.raw_sql|urlencode }}&params={{ query.params|urlencode }}&duration={{ query.duration|floatformat:"2"|urlencode }}&hash={{ query.hash }}">Sel</a>  							<a class="remoteCall" href="/__debug__/sql_explain/?sql={{ query.raw_sql|urlencode }}&params={{ query.params|urlencode }}&duration={{ query.duration|floatformat:"2"|urlencode }}&hash={{ query.hash }}">Expl</a> -							{% if is_mysql %} +							{% ifequal query.engine 'mysql' %}  								<a class="remoteCall" href="/__debug__/sql_profile/?sql={{ query.raw_sql|urlencode }}&params={{ query.params|urlencode }}&duration={{ query.duration|floatformat:"2"|urlencode }}&hash={{ query.hash }}">Prof</a> -							{% endif %} +							{% endifequal %}  						{% endif %}  					{% endif %}  					</td> @@ -56,6 +56,12 @@  					<td colspan="4">  						<div class="djSQLDetailsDiv">  							<p><strong>Connection:</strong> {{ query.alias }}</p> +							{% if query.iso_level %} +								<p><strong>Isolation Level:</strong> {{ query.iso_level }}</p> +							{% endif %} +							{% if query.trans_status %} +								<p><strong>Transaction Status:</strong> {{ query.trans_status }}</p> +							{% endif %}  							{% if query.stacktrace %}  								<pre>{{ query.stacktrace }}</pre>  							{% endif %} diff --git a/debug_toolbar/utils/compat/db.py b/debug_toolbar/utils/compat/db.py index f3b37e6..4273d9e 100644 --- a/debug_toolbar/utils/compat/db.py +++ b/debug_toolbar/utils/compat/db.py @@ -1,6 +1,13 @@ +from django.conf import settings  try:      from django.db import connections +    dbconf = settings.DATABASES  except ImportError:      # Compat with < Django 1.2      from django.db import connection -    connections = {'default': connection}
\ No newline at end of file +    connections = {'default': connection} +    dbconf = { +        'default': { +            'ENGINE': settings.DATABASE_ENGINE, +        } +    }
\ No newline at end of file diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py index 4c9ee53..de84785 100644 --- a/debug_toolbar/utils/tracking/db.py +++ b/debug_toolbar/utils/tracking/db.py @@ -10,7 +10,7 @@ from django.utils.encoding import force_unicode  from django.utils.hashcompat import sha_constructor  from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, get_template_info - +from debug_toolbar.utils.compat.db import connections  # TODO:This should be set in the toolbar loader as a default and panels should  # get a copy of the toolbar object with access to its config dictionary  SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \ @@ -29,6 +29,9 @@ class CursorWrapper(object):          self.logger = logger      def execute(self, sql, params=()): +        alias = getattr(self, 'alias', 'default') +        # HACK: avoid imports +        engine = connections[alias].connection.__class__.__module__.split('.', 1)[0]          start = datetime.now()          try:              return self.cursor.execute(sql, params) @@ -56,9 +59,9 @@ class CursorWrapper(object):                  pass              del cur_frame -            # We keep `sql` to maintain backwards compatibility -            self.logger.record(**{ -                'alias': getattr(self, 'alias', 'default'), +            params = { +                'engine': engine, +                'alias': alias,                  'sql': self.db.ops.last_executed_query(self.cursor, sql, params),                  'duration': duration,                  'raw_sql': sql, @@ -70,7 +73,18 @@ class CursorWrapper(object):                  'is_slow': (duration > SQL_WARNING_THRESHOLD),                  'is_select': sql.lower().strip().startswith('select'),                  'template_info': template_info, -            }) +            } + +            if engine == 'psycopg2': +                conn = connections[alias].connection +                params.update({ +                    'trans_status': conn.get_transaction_status(), +                    'iso_level': conn.isolation_level, +                    'encoding': conn.encoding, +                }) +             +            # We keep `sql` to maintain backwards compatibility +            self.logger.record(**params)      def executemany(self, sql, param_list):          return self.cursor.executemany(sql, param_list) diff --git a/example/example.db b/example/example.dbBinary files differ index 3ca0f39..c607f31 100644 --- a/example/example.db +++ b/example/example.db | 
