Log des requêtes SQL faites par l’ORM Django en temps réel


Même en recherchant sur les sites spécialisés en anglais, je tombe toujours sur des solutions basées sur la django-debug-toolbar, l’affichage de connection.queries ou l’usage de devserver. Ça a son utilité (surtout la fabuleuse django-debug-toolbar), mais c’est compliqué, long à mettre en oeuvre, et pas très pratique.

Il y a beaucoup plus simple, et le plus beau, c’est que Django le propose en natif.

Par default, Django loggue toutes les requêtes SQL dans django.db.backends si DEBUG = True. Il suffit donc de configurer le logger, dans votre settings.py:

import os
import tempfile
 
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'handlers': {
        'tempfile': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'formatter': 'verbose',
            'filename': os.path.join(tempfile.gettempdir(), 'django-debug.log'),
        },
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
            'formatter': 'simple'
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console', 'tempfile'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

Lancez ./manage.py shell:

In [1]: m = Table.objects.filter(title__isnull=False)
 
In [2]: m
DEBUG (0.018) SELECT "table"."id", "table"."title", "table"."original_title" FROM "table" WHERE "table"."title" IS NOT NULL LIMIT 21; args=()
Out[2]: [< Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, < Table object >, '...(remaining elements truncated)...']

Une version plus verbeuse sera aussi logguée dans un fichier temporaire. Par exemple, sous Linux il sera dans /tmp/django-debug.log.

Toutes les requêtes faites par le site Web seront également affichées dans le terminal sur lequel tourne le serveur, et dans le fichier temporaire.

Une fois que vous maitrisez le concept, je vous recommande plutot de mettre le logger django.db.backends dans votre local_settings.py, histoire d’éviter de l’avoir en prod :

LOGGING['loggers'].update({
        'django.db.backends': {
            'handlers': ['console', 'tempfile'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
)

Autre bénéfice, il suffit de commenter cette partie quand on ne souhaite plus afficher autant d’informations.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.