0

I would like to view the queries run inside a block of code, ideally getting it as a list of strings.

Of course there are similar SO questions and answers, but they do not address my three specific requirements:

  • Works for queries other than SELECT.
  • Works when the code is not in DEBUG mode.
  • The code executes normally, i.e. any production code runs as production code.

What I have so far is a transaction inside a DEBUG=True override, that is instantly rolled back after the queries are collected.

from contextlib import contextmanager
from django.conf import settings
from django.db import connections
from django.db import transaction
from django.test.utils import override_settings

@contextmanager
@override_settings(DEBUG=True)
def print_query():
    class OhNo(Exception):
        pass
    queries = []
    try:
        with transaction.atomic():
            yield
            for connection in connections:
                queries.extend(connections[connection].queries)
            print(queries)
            raise OhNo
    except OhNo:
        pass

def do_special_debug_thing():
    print('haha yes')

with print_query():
    Foo.objects.update(bar=1)
    if settings.DEBUG:
        do_special_debug_thing()

There are two problems with that snippet:

  • That DEBUG override doesn't do anything. The context manager prints out [].
  • If the DEBUG override is effective, then do_special_debug_thing is called, which I do not want to happen.

So, as far as I know, there is no way to collect all queries made inside a block of code, including those that are SELECT statements, while DEBUG is off. What ways are there to achieve this?

Brian
  • 7,394
  • 3
  • 25
  • 46
  • Take a look at this answer for collection all queries when debug is not on https://stackoverflow.com/a/30394237/6682340 – Krukas Jun 12 '19 at 16:04
  • @Krukas that's not really getting queries back as a list of strings, but better than having nothing definitely, will give it a go, thanks. – Brian Jun 12 '19 at 17:29

1 Answers1

0

If you would like to do that only once, getting queries separately and put them in a list could help you.

update = Foo.objects.filter(bar=1)
query = str(update.query)
print(query)
Danilo Akamine
  • 705
  • 7
  • 13
  • Well, the return of an `.update()` is the integer value of the number of rows updated, and the return of a `.delete()` is a dict. This is not a viable option. (Edit: it's an incorrect answer altogether, but I'll skip the downvoting because you tried to help.) – Brian Jun 12 '19 at 17:31
  • @Brian you are right. I was talking about logging the querysets. I just copied and paste your code and forgot to change to `filter()`. I'll fix. – Danilo Akamine Jun 12 '19 at 18:01
  • If you do that, your answer no longer satisfies the "Works for queries other than `SELECT`" part of the question. – Brian Jun 12 '19 at 18:19