6.

Django モデルインスタンスの中身を確認する方法(__dict__ / shell / dir / pprint / SQL ログ)

編集
この記事の要点
  • Django のモデルインスタンスの内部状態は instance.__dict__フィールド辞書として確認できる
  • 対話的に試すなら python manage.py shell(または shell_plus)で print(model.__dict__) が最短
  • _meta.get_fields() でモデルが持つ全フィールド定義を取得できる(DB に保存されていない状態でも可)
  • 関連フィールド(FK / M2M)は __dict__ には ID のみ。実体を見るには obj.related で再アクセス
  • クエリ発行回数や実 SQL を確認するなら connection.queries、または django-debug-toolbar

背景

Django でモデルを作って save() したあと、「いまこのインスタンスにはどんな値が入っているのか」を確認したい場面は頻繁にあります。フォームから受け取った値・自動付与された ID・signal で書き換わった値などを、デバッグ時に素早く見るための定番手段を整理します。

1. 最短: __dict__ で覗く

Python のオブジェクトは内部の属性辞書を __dict__ で取り出せます。Django のモデルインスタンスもこれが効きます。

from myapp.models import SampleModel

obj = SampleModel.objects.get(id=1)
print(obj.__dict__)

出力イメージ:

{
  '_state': <django.db.models.base.ModelState object at 0x...>,
  'id': 1,
  'name': 'sample',
  'price': 1200,
  'category_id': 3,
  'created_at': datetime.datetime(2026, 6, 11, 10, 0, 0, ...),
}

このダンプには次のような特徴があります。

  • 先頭の _state は Django 内部用(DB 接続情報・new/old 判定)。無視して OK
  • 外部キーは 属性名 + _id(例: category_id)で生 ID が入る
  • ManyToMany は __dict__ に出てこない(中間テーブル経由のため)
  • DB から取得した直後は _state.adding == False、新規 SampleModel(id=1) しただけだと True

見栄え重視で確認したいときは pprint が便利です。

from pprint import pprint
pprint(obj.__dict__)

2. Django shell で対話確認

対話的に試すなら manage.py shell がもっとも手軽です。プロジェクトの設定を読み込んだ状態で Python REPL に入れます。

python manage.py shell
>>> from myapp.models import SampleModel
>>> obj = SampleModel.objects.get(pk=1)
>>> obj.__dict__
>>> dir(obj)            # 利用可能な属性・メソッド一覧
>>> obj._meta.get_fields()  # モデル定義上のフィールド一覧

外部パッケージ django-extensions を入れていれば python manage.py shell_plus でモデルが自動 import されるため、import 文を書かずに即座に試せます。

3. モデル定義そのものを確認: _meta

__dict__ はインスタンスの値ですが、_meta は「モデル定義」を持つ内部 API です。フィールド名・型・関連の方向などを動的に取り出せます。

for f in SampleModel._meta.get_fields():
    print(f.name, type(f).__name__)

出力例:

id AutoField
name CharField
price IntegerField
category ForeignKey
created_at DateTimeField

4. 関連オブジェクト(FK / M2M)を実体で見る

__dict__ に出るのは ID だけなので、関連先の実データを見たいときは属性経由で取得します。

obj = SampleModel.objects.select_related('category').get(pk=1)
print(obj.category)            # 関連先のインスタンス
print(obj.category.__dict__)   # その中身

# ManyToMany
for tag in obj.tags.all():
    print(tag.name)

select_related / prefetch_related を付けずに obj.category を参照すると、追加 SQL が発行されます(N+1 問題)。

5. SQL ログを確認する

「内部でどんな SQL が発行されたか」を見たいときは django.db.connection.queries を使います(DEBUG=True のとき有効)。

from django.db import connection, reset_queries
reset_queries()

obj = SampleModel.objects.get(pk=1)
print(obj.category.name)

for q in connection.queries:
    print(q['time'], q['sql'])

本格的にチューニングするなら django-debug-toolbar をインストールして、画面右側のパネルから 1 リクエスト分の SQL とテンプレ描画時間を可視化するのが定番です。

6. 「保存前」と「保存後」の差分を見る

フォームから受け取った値が DB に書き込まれる前にどう変わったか、を確認したい場合は pre_save / post_save シグナルや、モデルの _state.adding を見るのが定石です。

obj = SampleModel(name='draft')
print(obj._state.adding)   # True(DB に未保存)
obj.save()
print(obj._state.adding)   # False
print(obj.__dict__)        # id が割り当てられている

7. シリアライズして JSON で見る

API レスポンスと同じ形式で見たい場合は、DRF の ModelSerializer や Django 標準の django.core.serializers を使います。

from django.core.serializers import serialize

print(serialize('json', [obj], indent=2))

よくあるハマり所

  • __dict__ に M2M は出ない → obj.tags.all() で個別取得
  • __dict__property 経由の派生値は出ない → vars(obj) でも同じ。属性アクセスする
  • DB から取り直さずに変更後の状態を見ると古い値が残る → obj.refresh_from_db() で再ロード
  • signal で書き換わる項目は save() 後の __dict__ で確認する

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. Model の定義方法
  2. マイグレーションファイルの作成
  3. テーブル定義の確認
  4. テーブルの作成
  5. テーブル名 = アプリケーション名 + モデル名の設定変更
  6. モデルの中身を確認

最近更新/作成されたページ