Django ORM を使っていると、どういった SQL が発行されているか、クエリの内容を出力したいときが多々あります。
SQL を出力する方法についてはいくつか方法がありますが、今回はその方法を思いつく限りピックアップしてみようと思います。
- 1)QuerySet の query を print する
- 2)DefaultConnectionProxy の queries を出力する
- 3)django-debug-toolbar の SQL Panel を使う
- 4)django-debug-toolbar の debugsqlshell を使う
- 5)django-extensions の shell_plus を --print-sql オプションで起動する
- 6)django.db.backends のログレベルを動的に変更
- 7)settings.py の LOGGING を設定
- まとめ
1)QuerySet の query を print する
個人的に一番よく使う方法。
実際に SQL を発行せずに、発行予定の SELECT文を出力することができます。
Django shell だろうが、pdb デバッグ中だろうが、PyCharm のデバッグ中だろうが、いつでも利用することができます。
例えば、Django shell で使う場合はこんな感じ。
$ python manage.py shell >>> from django.contrib.auth.models import User >>> print User.objects.filter(pk=1).query SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1
事前に何も設定しなくても、デバッグ中に手っ取り早く発行された SQL が確認できるのが特徴です。しかしながら、発行された SQL をリアルタイムに確認することはできません。
(参考)How can I see the raw SQL queries Django is running? - Stack Overflow
2)DefaultConnectionProxy の queries を出力する
直前に発行された SQL を確認することができます。
1)とセットで使うことが多いでしょうか。
$ python manage.py shell >>> from django.contrib.auth.models import User >>> User.objects.filter(pk=1) [<User: user-1>] >>> User.objects.filter(pk=2) [<User: admin>] >>> from django.db import connection >>> connection.queries [{u'time': u'0.000', u'sql': u'SET SQL_AUTO_IS_NULL = 0'}, {u'time': u'0.000', u'sql': u'SET SQL_AUTO_IS_NULL = 0'}, {u'time': u'0.000', u'sql': u'SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1 LIMIT 21'}, {u'time': u'0.001', u'sql': u'SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 2 LIMIT 21'}] >>> connection.queries[-1] {u'time': u'0.001', u'sql': u'SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 2 LIMIT 21'}
発行したクエリは、'time'(実行時間)と 'sql' の dict として、発行された順に後ろに追加されていきます。慣れるまで、出力内容が少し読みにくいのが難点でしょうか。
またこちらの方法でも、発行された SQL をリアルタイムに確認することはできません。
(参考)How can I see the raw SQL queries Django is running? - Stack Overflow
3)django-debug-toolbar の SQL Panel を使う
プラグインのインストールが必要な物の、一番楽チンな方法。
Django を runserver で起動して、実際に画面を操作してから、右側に表示される SQL Panel を開いて確認するだけです。
django-debug-toolbar の SQL Panel を使うには、条件がいくつかあります。
- DEBUG = True
- 'django.contrib.staticfiles' が INSTALLED_APPS に設定済み *1
他にも、settings.py に以下の設定が必要です。 *2
INSTALLED_APPS += ('debug_toolbar',) def always_show_toolbar(request): return True DEBUG_TOOLBAR_CONFIG = { 'SHOW_TOOLBAR_CALLBACK': '%s.always_show_toolbar' % __name__, }
このように、画面からサクサクっと操作が可能です。楽チンですね。
インストール方法
$ pip install django-debug-toolbar
ちなみに、検証時の環境は以下の通りでした。
- Python 2.7.6
- Django (1.9.8)
- django-debug-toolbar (1.5)
django-debug-toolbar のさらに詳しい説明については、以下の書籍が非常に有用です。「14-04 Django Debug Toolbar」の章に詳しい説明が載っています。
Django 以外にも、Python での開発手法についてのノウハウがいろいろ詰まっていてオススメです。
- 作者: ビープラウド
- 出版社/メーカー: 秀和システム
- 発売日: 2015/02/27
- メディア: 単行本
- この商品を含むブログ (4件) を見る
(参考)
- Installation — Django Debug Toolbar 1.9 documentation
- http://qiita.com/seizans/items/ff9da996070105707bcc
4)django-debug-toolbar の debugsqlshell を使う
3)の django-debug-toolbar をインストールしているのであれば、通常の Django shell ではなく debugsqlshell を起動することで、発行される SQL を随時確認することができます。
$ python manage.py debugsqlshell >>> from django.contrib.auth.models import User >>> User.objects.filter() SET SQL_AUTO_IS_NULL = 0 [0.80ms] SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` LIMIT 21 [0.19ms] [<User: admin>]
5)django-extensions の shell_plus を --print-sql オプションで起動する
「django-extensions」は、「Django フレームワークの機能を便利に拡張する、管理コマンドやデータベースフィールドなどの詰め合わせ」 *3 です。
django-extensions の shell_plus を --print-sql オプションで起動すれば、4)と同じような機能を使うことができます。
$ python manage.py shell_plus --print-sql >>> from django.contrib.auth.models import User >>> User.objects.filter() SET SQL_AUTO_IS_NULL = 0 Execution time: 0.000056s [Database: default] SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` LIMIT 21 Execution time: 0.000391s [Database: default] [<User: admin>]
この shell_plus には autoloading という機能があるらしいのですが、正直なところ使ったことはありません。
インストール方法
$ pip install django-extensions
settings.py に「django_extensions」を追加。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django_extensions', ]
(参考)
- django shellで実行されるsqlを表示する - Misc Notes
- GitHub - django-extensions/django-extensions: This is a repository for collecting global custom management extensions for the Django Framework.
6)django.db.backends のログレベルを動的に変更
事前の準備がほとんど必要なく、1)や 2)のように明示的に SQL を出力する必要がないので、お手軽に使えます。
Django shell で使うケースが多いかもしれません。
$ python manage.py shell >>>import logging >>>l = logging.getLogger('django.db.backends') >>>l.setLevel(logging.DEBUG) >>>l.addHandler(logging.StreamHandler()) >>> from django.contrib.auth.models import User >>> User.objects.filter(pk=1) (0.000) SET SQL_AUTO_IS_NULL = 0; args=None (0.000) SET SQL_AUTO_IS_NULL = 0; args=None (0.000) SELECT `auth_user`.`id`, `auth_user`.`password`, `auth_user`.`last_login`, `auth_user`.`is_superuser`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1 LIMIT 21; args=(1,) [<User: user-1>]
7)settings.py の LOGGING を設定
ログに出力したり、コンソールに出力したりと、いろいろ柔軟に設定可能です。リアルタイムに発行される SQL が確認できるのも、この方法の特徴です。
なお、「DEBUG = True」でないと使えないので注意が必要です。
settings.py の設定例
DEBUG = True LOGGING = { 'disable_existing_loggers': False, 'version': 1, 'handlers': { 'console': { # logging handler that outputs log messages to terminal 'class': 'logging.StreamHandler', 'level': 'DEBUG', # message level to be written to console }, }, 'loggers': { '': { # this sets root level logger to log debug and higher level # logs to console. All other loggers inherit settings from # root level logger. 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, # this tells logger to send logging message # to its parent (will send if set to True) }, 'django.db': { # django also has database level logging 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, }, }, }
ただしこの方法だと、ログやコンソールが大量の SQL ですぐに埋め尽くされてしまうので、1)や 2)の方法を使って、確認したい SQL だけをピンポイントに出力するようにした方が開発中は捗るかもしれません。
(参考)django - log all sql queries - Stack Overflow
まとめ
今回は、Django ORM の SQL を出力する方法として7種類のやり方を紹介しました。
この中から、目的や状況に応じてやり方を使い分けるようにすると、開発の効率もグンとアップすると思います。
良い Django ライフを!