programing

django 테스트를 실행할 때 sql 쿼리를 보는 방법은 무엇입니까?

easyjava 2023. 6. 13. 22:55
반응형

django 테스트를 실행할 때 sql 쿼리를 보는 방법은 무엇입니까?

django 애플리케이션 유닛 테스트 중 하나가 실패함

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

이 오류의 원인이 된 실제 SQL 쿼리를 보고 싶습니다.당신은 그것을 달성하는 방법을 알고 있습니까?

다른 옵션은 다음과 같습니다.CaptureQueriesContext(와 함께 제공됨.pytest).

from django.db import connection
from django.test.utils import CaptureQueriesContext


def test_foo():
    with CaptureQueriesContext(connection) as ctx:
        # code that runs SQL queries
        print(ctx.captured_queries)

출처:

테스트에서 모든 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만약 당신이 그것을 무시한다면요.

또한 다음을 수행하여 쿼리를 가져올 수 있습니다(예를 들어, 인쇄하거나 테스트에서 평가).

사실 요즘은 당신이 변하면 안되기 때문에 제가 사용합니다.

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또한 적합할 수도 있습니다. 답변의 차이점을 참조하십시오.

SQL 출력에 대한 자세한 내용은 Django 설명서를 참조하십시오.

다른 옵션은 다음과 같이 테스트에 사용하는 것입니다.

from django.db import connection

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로 테스트했습니다.

가장 깨끗한 솔루션은 아니지만 추가 패키지를 설치하지 않고 빠르게 디버깅하고 싶다면 django/db에서 execute() 메서드를 찾을 수 있습니다.

Oracle의 경우 다음과 같은 이점이 있습니다.

django/db/backends/backends/base.py 에서 다음을 찾습니다.

def execute

Postgre용SQL 위치:

django/db/backends/postgresql_psycopg2/base.파이의

CursorWrapper에는 execute() 메서드가 있습니다.

둘 다 IntegrityError와 DatabaseError를 잡습니다. 여기에 인쇄문을 추가할 수 있습니다.

모든 sql 쿼리를 보고 싶은 ppl의 경우 함수 호출 바로 뒤에 print 문을 놓으십시오.

의 경우에는pytest그리고.pytest-django그냥 그것을 위한 고정 장치를 만듭니다.

@pytest.fixture
def debug_queries(db):
    """ Because pytest run tests with DEBUG=False
        the regular query logging will not work, use this fixture instead
    """
    from django.db import connection
    from django.test.utils import CaptureQueriesContext
    with CaptureQueriesContext(connection):
        yield connection

그렇다면 당신의 테스트에서.

@pytest.mark.django_db
def test__queries(debug_queries):
    # run your queries here

물론 로깅 구성은 다음과 같은 쿼리 로깅을 활성화해야 합니다.

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': '%(asctime)s - %(levelname)s - %(name)s - %(message)s',
        },
    },
    'handlers': {
        'default': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'standard',
            'stream': 'ext://sys.stdout',
        },
    },
    'loggers': {
        'django.db.backends': {
            'level': 'DEBUG',
            'handlers': ['default'],
            'propagate': False,
        },
    }
}

지금까지 찾은 가장 좋은 해결책은 django-debug toolbar에서 제공하는 debugsqlshell custom django management 명령입니다.

설정에서 콘솔 수준을 DEBUG로 변경할 수 있습니다.장고 1.9에서 작동했습니다.

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

이것이 저에게 효과적인 솔루션이었습니다(Django 3.1).

from django.test import TestCase


class TestSomething(TestCase):
    @override_settings(DEBUG=True)
    def test_something(self):
        pass
    
    def tearDown(self):
        from django.db import connection
        for query in connection.queries:
            print(f"✅ {query['sql']}\n")

원천

여기에 있는 모든 옵션은 너무 복잡했습니다. 그리고 너무 많은 것들이 잘못될 수 있습니다.작동합니다.django>=1.11+<=4.x[그것을 위에 올려놓습니다.mainbranch] (미래에 그들이 그것을 깰 때까지...)

무시함으로써 작동합니다.settings.DEBUG예요.CursorDebugWrapper항상 사용되므로 실행된 SQL을 기록할 수 있습니다.

import inspect
from collections import deque
from contextlib import contextmanager
from unittest import mock

from django.db import connections
from django.db.backends import utils


@contextmanager
def print_queries(using="default"):
    """
    [debug] Prints out all the queries in real time

    To avoid messing with django's logging and get the SQL working inside
    tests where `DEBUG` can be set to `False`, this bypasses all that and
    goes straight for the kill.

    Example:

        class TestSomething(TestCase):
            def test_something(self):
                with print_queries():
                    Model.objects.create(a=1, b=2)

        def test_something():
            with print_queries():
                Model.objects.create(a=1, b=2)

    """

    def fake_maker(self, cursor):
        """
        Normally `make_cursor` uses `CursorWrapper` which does NOT debug.
        """
        return utils.CursorDebugWrapper(cursor, self)

    class Snitch(deque):
        """
        Modified version of `deque` that `print()`s out all the items inserted to it.
        """

        def append(self, item):
            current_frame = inspect.currentframe().f_back
            while True:
                info = inspect.getframeinfo(current_frame)
                if "/django/" in info.filename:
                    current_frame = current_frame.f_back
                    continue
                break

            print("*", item["sql"], item["time"], f"{info.filename}:{info.lineno}")
            return super().append(item)

    connection_ = connections[using]
    mock_maker = mock.patch("django.db.backends.base.base.BaseDatabaseWrapper.make_cursor", fake_maker)
    mock_deque = mock.patch.object(connection_, "queries_log", Snitch(maxlen=connection_.queries_log.maxlen))

    with mock_maker, mock_deque:
        yield

다음과 같이 사용합니다.

def test_whatever():
    ...
    with print_queries():
        Model.objects.create(a=1, b=2)  # any query here
    ...

출력은 다음과 같습니다.

* SELECT .. FROM "table" WHERE ... 0.001 /full/path/file.py:136
* SELECT .. FROM "table" WHERE ... 0.001 /full/path/file.py:245

코드에서 쿼리가 수행되는 위치를 알려줍니다.

언급URL : https://stackoverflow.com/questions/13162771/django-how-to-see-sql-query-when-running-tests

반응형