Django, как увидеть sql-запрос при выполнении тестов?

Одно из моих приложений django unit test выходит из строя с

DatabaseError: ORA-00942: table or view does not exist

Я бы хотел увидеть фактический SQL-запрос, вызвавший эту ошибку. Вы знаете, как достичь этого?

Ответ 1

Лучшим решением, которое я нашел до сих пор, является команда dzhango управления debugsqlshell, предоставляемая django-debugtoolbar.

Ответ 2

Если вы хотите печатать/записывать все SQL-запросы из тестов, попробуйте подклассифицировать TestCase следующим образом:

from django.conf import settings
from django.template import Template, Context
import sys
from django.db import connection
from django.test import TestCase

class LoggingTestCase(TestCase):

  @staticmethod
  def setUpClass():
    # The test runner sets DEBUG to False. Set to True to enable SQL logging.
    settings.DEBUG = True
    super(LoggingTestCase, LoggingTestCase).setUpClass()

  @staticmethod
  def tearDownClass():
    super(LoggingTestCase, LoggingTestCase).tearDownClass()

    time = sum([float(q['time']) for q in connection.queries])
    t = Template("{{count}} quer{{count|pluralize:\"y,ies\"}} in {{time}} seconds:\n\n{% for sql in sqllog %}[{{forloop.counter}}] {{sql.time}}s: {{sql.sql|safe}}{% if not forloop.last %}\n\n{% endif %}{% endfor %}")
    print >> sys.stderr, t.render(Context({'sqllog': connection.queries, 'count': len(connection.queries), 'time': time}))

    # Empty the query list between TestCases.    
    connection.queries = []

Затем используйте LoggingTestCase вместо TestCase как базовый класс в ваших тестах. Не забывайте называть это tearDownClass, если вы его переопределите.

Ответ 3

Вы также можете сделать следующее, чтобы получить запросы (а затем, например, распечатать или оценить его в своем тесте).

На самом деле вы не должны изменять django.conf.settings настоящее время, поэтому я использую override_settings.

from django.db import connection, reset_queries
from django.test import override_settings, TransactionTestCase

class TransactionTests(TransactionTestCase):

    @override_settings(DEBUG=True)
    def test_sql(self):
        reset_queries()
        try:
            # Code that uses the ORM goes here
        except Exception as e:
            pass
        self.assertEqual(connection.queries, [])

TestCase также может подойти, см. Различия в этом ответе.

См. Документацию Django для деталей для вывода SQL.

Ответ 4

Это не самое чистое решение, но если вы просто захотите отлаживать без установки дополнительных пакетов, вы можете искать метод execute() в django/db.

Для Oracle, я думаю, он находится в:

django/db/backends/oracle/base.py и найдите:

def execute

Для PostgreSQL он находится в:

Джанго/дб/бэкэнды/postgresql_psycopg2/base.py

В CursorWrapper существует метод execute().

Оба ловут IntegrityError и DatabaseError, вы можете добавить там инструкцию печати. ​​

Для ppl, которые хотят видеть все SQL-запросы, поставьте инструкцию печати сразу после вызова функции.

Ответ 5

Вы можете изменить уровень консоли до DEBUG в настройках. Он работал на Django 1.9.

LOGGING = {
...
'handlers': {
    'console': {
        'level': 'DEBUG',
        'class': 'logging.StreamHandler',
        'formatter': 'simple'
        },
    }
...
}

Ответ 6

Другой вариант - использовать connection.execute_wrapper() в вашем тесте следующим образом:

def logger(execute, sql, params, many, context):
    print(sql, params)
    return execute(sql, params, many, context)

class GizmoTest(TestCase):

    def test_with_sql_logging(self):
        with connection.execute_wrapper(logger):
            code_that_uses_database()

Протестировано с Django 2.2.