ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
方法 1: settings.py で全 SQL をログに出す
# settings.py
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"sql": {"format": "[%(asctime)s] %(message)s"},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "sql",
},
},
"loggers": {
"django.db.backends": {
"handlers": ["console"],
"level": "DEBUG", # ここを DEBUG にすると SQL が出る
"propagate": False,
},
},
}
実行すると、かかった秒数付きで次のように出力されます。
(0.001) SELECT "app_user"."id", "app_user"."name" FROM "app_user" WHERE "app_user"."active"; args=(True,)
重要な制約: このロガーは settings.DEBUG = True のときしか動きません。Django が SQL を記録するかどうかを DEBUG で切り替えているためです。本番で確認したい場合は、後述のデータベース側のログを使ってください。
方法 2: 特定のクエリの SQL だけ見る
qs = User.objects.filter(active=True).order_by("-created_at")[:10]
print(qs.query) # 実行せずに SQL 文字列を得る
# SELECT "app_user"."id", ... FROM "app_user" WHERE "app_user"."active" = True
# ORDER BY "app_user"."created_at" DESC LIMIT 10
# パラメータを分けて見たいとき
print(qs.query.sql_with_params())
# 実行計画まで見たいとき(PostgreSQL / MySQL)
print(qs.explain())
print(qs.explain(analyze=True))
qs.query の出力は値が埋め込まれた見た目になり、そのまま DB に貼っても動かない場合があります。原因調査には十分ですが、正確な発行内容は次の connection.queries で確認してください。
方法 3: 実行済みクエリの一覧
from django.db import connection, reset_queries
reset_queries() # 計測開始
users = list(User.objects.all())
for u in users:
print(u.profile.nickname) # ここで N+1 が起きる
print(len(connection.queries)) # 発行された本数
for q in connection.queries:
print(q["time"], q["sql"][:120])
connection.queries も DEBUG = True のときだけ蓄積されます。長時間動くプロセスではメモリを食い続けるので、区切りごとに reset_queries() を呼びます。
N+1 問題を見つける
from django.db import connection, reset_queries
from contextlib import contextmanager
@contextmanager
def count_queries(label):
reset_queries()
yield
print(f"{label}: {len(connection.queries)} 本")
with count_queries("最適化なし"):
for u in User.objects.all():
print(u.profile.nickname) # 1 + N 本
with count_queries("select_related"):
for u in User.objects.select_related("profile"):
print(u.profile.nickname) # 1 本(JOIN される)
with count_queries("prefetch_related"):
for u in User.objects.prefetch_related("orders"):
print(len(u.orders.all())) # 2 本(別クエリでまとめて取得)
| 関係 | 使うもの |
|---|---|
ForeignKey / OneToOneField(1 対 1・多対 1) | select_related() |
逆参照 / ManyToManyField(1 対多・多対多) | prefetch_related() |
方法 4: django-debug-toolbar
pip install django-debug-toolbar
# settings.py
INSTALLED_APPS += ["debug_toolbar"]
MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware")
INTERNAL_IPS = ["127.0.0.1"]
# urls.py
from django.urls import include, path
import debug_toolbar
urlpatterns += [path("__debug__/", include(debug_toolbar.urls))]
画面の右側にパネルが出て、SQL の本数・実行時間・重複回数・実行計画が一覧できます。「同じクエリが 50 回」といった表示が出れば N+1 です。開発環境専用なので、INSTALLED_APPS への追加は if DEBUG: で囲んでください。
本番で SQL を確認したいとき
DEBUG = True を本番で有効にしてはいけません。設定値やソースコードが画面に露出します。本番ではデータベース側のログを使います。
-- MySQL: 遅いクエリだけ残す
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 1 秒以上
SHOW VARIABLES LIKE 'slow_query_log_file';
-- PostgreSQL: postgresql.conf
-- log_min_duration_statement = 1000 (ミリ秒)
-- SELECT pg_reload_conf();
アプリ側で残したい場合は、connection.execute_wrapper() で自前のフックを差し込む方法もあります。こちらは DEBUG に依存しません。
import logging
import time
from django.db import connection
logger = logging.getLogger("sql")
def log_slow(execute, sql, params, many, context):
start = time.monotonic()
try:
return execute(sql, params, many, context)
finally:
elapsed = time.monotonic() - start
if elapsed > 0.5: # 0.5 秒以上だけ記録
logger.warning("slow %.3fs %s", elapsed, sql[:500])
# ミドルウェアやビューの中で
with connection.execute_wrapper(log_slow):
list(User.objects.all())
SQL には検索条件として個人情報が入り得ます。ログに残す前に、出力先の権限と保存期間を決めておいてください。
関連
- django — 親カテゴリ
- ログ出力方法 — アプリのログ全般
- ログのローテート設定
- データベースへの接続と操作
- filterの検索オプション
- 素のSQLを直接実行する方法
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
- 環境構築とプロジェクト/アプリの作成
- MVC(MVT)のそれぞれの使い方と説明
- データベースへの接続と操作
- Django Administration
- git管理
- エラー一覧
- バージョンの確認方法
- ログ出力方法
- SQLのログ出力方法
- ログのローテート設定
- settings.pyの定数にアクセスする方法
- 本番環境へのインストールとアプリのデプロイ(apache編)
- 本番環境へのインストールとアプリのデプロイ(nginx編)
- djangoアプリの本番の開始URLを変更する
- 静的(static)ファイルの置き場所と読み込み(画像、css、js )
- CSRFトークンをAjaxで使用する方法
- ajaxの使用例(POST編)
- ファイルのアップロードとファイルの名前
- クイックスタート/チュートリアル
- ログイン機能
- テンプレート側のログイン判定
- ビュー側のログイン判定
- 管理者ユーザーの作成/判定と管理画面
- モデルのjson化とレスポンス
- runserverでポートを指定する方法
- cronによるバッチ実行
- テンプレートで利用する共通のcontextを定義する方法
- プログラムが本番サーバーで反映されない場合の対処法
- APIの作成
- cron用コマンド・ファイルの作成
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- 【django】ログイン 認証機能 2026-09-08 03:22:09
- MySQL ERROR 1063 Incorrect column specifier for column|原因と直し方 2026-09-08 03:11:09
- 【PHPエラー】Object of class stdClass could not be converted to string 2026-09-07 07:46:04
- Julia Genie ローカル開発サーバ起動完全ガイド 2026-09-07 07:46:04
- Wi-Fi とは|規格と世代(Wi-Fi 4〜7)・周波数帯・CSMA/CA・WPA3 NEW 2026-09-07 07:45:13
- set コマンドでシェルオプションと位置パラメータを操作 | bash 2026-09-07 07:45:13
- JPEG(.jpg/.jpeg)画像形式の完全ガイド — 仕様・マジックナンバー・他形式との比較・EXIF 2026-09-07 07:45:13
- UE5 Get Overlapping Actorsで特定クラスだけ処理|Class Filter・Cast To 2026-09-07 07:45:13
- Linuxで特定拡張子のファイルを再帰削除|find -deleteの安全手順 2026-09-07 07:45:13
- Django CBVでテンプレートに値を渡す|get_context_data・extra_context 2026-09-07 07:45:13
- Linuxで複数ファイルの文字列を一括置換|find・sed・xargsの安全手順 2026-09-07 07:45:13
- Laravelルートグループ|prefix・middleware・nameで一括管理 2026-09-07 07:45:13
- Linux whichコマンドの使い方|絶対パス取得とtype・command -vの違い 2026-09-07 07:45:13
- Linux catコマンドの使い方|行番号表示・複数ファイル連結 2026-09-07 07:45:13
- unable to execute 'gcc': No such file or directory 2026-09-07 07:45:13
コメントを削除してもよろしいでしょうか?