Django ORM (Object-Relational Mapping、オブジェクト リレーショナル マッピング) を使用すると、開発者は SQL を直接記述することなく、Python を使用してリレーショナル データベースを操作できます。
ORM は、データベース内のテーブルを Python Model にマップし、データベース レコードを Model インスタンスにマップし、QuerySet でデータベース クエリを構築して実行します。
1. 基本的なクエリ
| Django ORM | SQL |
|---|---|
Model.objects.all() | SELECT * FROM table |
Model.objects.get(id=1) | SELECT * FROM table WHERE id=1 |
Model.objects.filter(name="A") | SELECT * FROM table WHERE name='A' |
Model.objects.first() | SELECT ... LIMIT 1 |
Model.objects.last() | 最後のアイテムを順番に取得する |
Model.objects.none() | 空の QuerySet を返します |
の主な違い:
all(): すべてのレコードから構成される QuerySet を返します。filter(): 条件を満たし、0 個以上のレコードが含まれる QuerySet を返します。get(): QuerySet ではなく、単一の Model オブジェクトを返します。first()、last(): 単一のオブジェクトまたはNoneを返します。none(): レコードなしで QuerySet を返します。
注: get() は、レコードが見つからない場合は DoesNotExist をスローし、複数のレコードが一致した場合は MultipleObjectsReturned をスローします。
また、get() は単に LIMIT 1 と同等ではありません。 Django は通常、制限されたクエリを使用して、複数のレコードが一致したかどうかを判断するのに十分な結果を取得します。
2.WHERE条件
Django 二重下線 __ を使用してフィールド検索条件 (Field Lookup) を表します。
| Django ORM | SQL / 意味 |
|---|---|
filter(id=1) | WHERE id = 1 |
filter(id__exact=1) | WHERE id = 1 |
filter(id__gt=1) | WHERE id > 1 |
filter(id__gte=1) | WHERE id >= 1 |
filter(id__lt=10) | WHERE id < 10 |
filter(id__lte=10) | WHERE id <= 10 |
filter(id__in=[1,2,3]) | WHERE id IN (1,2,3) |
filter(name__contains="a") | 文字列 a が含まれます |
filter(name__icontains="a") | 大文字と小文字を含む一致を無視する |
filter(name__startswith="A") | Aから始める |
filter(name__endswith="A") | Aで終わる |
filter(name__iexact="abc") | 大文字と小文字を区別しない完全一致 |
filter(name__isnull=True) | WHERE name IS NULL |
filter(name__isnull=False) | WHERE name IS NOT NULL |
exclude(id=1) | id=1 のレコードを除外する |
filter(price__range=(10,100)) | WHERE price BETWEEN 10 AND 100 |
Lookup の一般的に使用される意味:
exact: 完全一致。contains: が含まれます。icontains: 大文字と小文字を含む一致を無視します。iexact: 大文字と小文字を区別しない完全一致。gt、gte: より大きい、以上。lt、lte: 以下、以下。in: 指定されたコレクションに属します。isnull: SQL NULLかどうかを判定します。
注: icontains などの大文字と小文字を区別しないクエリの実際の動作は、データベース照合順序 (Collation) の影響を受ける可能性があります。
日付クエリ
モデルに created_at フィールドがあると仮定します。
| Django ORM | 意味 |
|---|---|
filter(created_at__year=2026) | 2026 年のデータをクエリする |
filter(created_at__month=10) | 10月のデータをクエリする |
filter(created_at__date=date(2026,10,25)) | 指定した日付を問い合わせる |
filter(created_at__gte=start) | 指定した時間後のデータをクエリする |
filter(created_at__range=(start,end)) | 指定された時間範囲内のデータをクエリする |
実際の開発では、特定の日にすべてのレコードをクエリする必要がある場合は、通常、左クローズおよび右オープンの時間範囲を使用できます。
Model.objects.filter(
created_at__gte=start,
created_at__lt=end,
)
これは、DateTimeField を使用する場合に特によく発生します。
3. AND / OR / NOT 条件
from django.db.models import Q
Q は、& (AND)、| (OR)、~ (NOT) をサポートする複雑なクエリ条件を構築するために使用されます。
| Django ORM | SQL |
|---|---|
filter(a=1, b=2) | WHERE a=1 AND b=2 |
filter(Q(a=1) & Q(b=2)) | WHERE a=1 AND b=2 |
filter(Q(a=1) | Q(b=2)) | WHERE a=1 OR b=2 |
filter(~Q(a=1)) | a=1 を除く |
filter(Q(a=1) & ~Q(b=2)) | a=1 かつ b=2 を満たさない |
複雑な条件の例:
Model.objects.filter(
Q(name__icontains="Tokyo")
| Q(name__icontains="Kyoto"),
score__gte=80,
)
対応するロジック:
WHERE
(name LIKE '%Tokyo%' OR name LIKE '%Kyoto%')
AND score >= 80
注:
- いくつかの一般的なキーワード引数は、デフォルトで AND を使用します。
Qはネストして組み合わせることができ、複雑な式には括弧を使用することをお勧めします。filter()でQパラメータとキーワード パラメータを混合する場合は、Qパラメータを最初に配置する必要があります。- NULL を許容するフィールドを否定する場合は、SQL NULL の扱いに注意が必要です。すべての場合を単純に
NOT (フィールド=値)と解釈することはできません。
4. SELECT: 戻りフィールドを指定します
| Django ORM | SQL / 機能 |
|---|---|
values("id","name") | SELECT id,name |
values_list("id","name") | QuerySet で構成されるタプルを返します |
values_list("id",flat=True) | 単一のフィールド値で構成される QuerySet を返します。 |
only("id","name") | 指定されたモデルフィールドのみをすぐにロードします |
defer("description") | 指定されたフィールドの遅延読み込み |
distinct() | SELECT DISTINCT |
valuesとonlyの違い
# 辞書を返す
Model.objects.values("id", "name")
# 戻る Model 例
Model.objects.only("id", "name")
values() は通常の Model インスタンスを構築しませんが、only() はいくつかのフィールドを遅延ロードするだけの Model インスタンスを返します。
遅延フィールドの場合、後でアクセスされると追加の SQL クエリがトリガーされる可能性があります。
5. ORDER BY
| Django ORM | SQL |
|---|---|
order_by("id") | ORDER BY id ASC |
order_by("-id") | ORDER BY id DESC |
order_by("-score","id") | ORDER BY score DESC, id ASC |
order_by("?") | ランダムな順序 |
Model.objects.order_by("-score", "id")
優先度はscoreの降順、同時タイムシェアはidの昇順となります。
注: ランダムな並べ替えでは、データ量が大きい場合、パフォーマンスに重大なオーバーヘッドが発生する可能性があります。
6. LIMIT / OFFSET
| Django ORM | SQL |
|---|---|
[:10] | LIMIT 10 |
[10:20] | LIMIT 10 OFFSET 10 |
[20:30] | LIMIT 10 OFFSET 20 |
例:
Model.objects.order_by("id")[10:20]
結果の順序が不確実になるのを防ぐために、ページングの際には安定した並べ替えを使用することをお勧めします。
大規模なデータの場合、OFFSET が大きくなるとクエリ効率が低下する可能性があるため、主キーまたはカーソルに基づくページングを検討できます。
7. Aggregate: 集計関数
from django.db.models import Count, Sum, Avg, Max, Min
| Django ORM | SQL |
|---|---|
aggregate(Count("id")) | SELECT COUNT(id) |
aggregate(Sum("price")) | SELECT SUM(price) |
aggregate(Avg("score")) | SELECT AVG(score) |
aggregate(Max("score")) | SELECT MAX(score) |
aggregate(Min("score")) | SELECT MIN(score) |
例:
Model.objects.aggregate(
total=Count("id"),
avg_score=Avg("score"),
max_score=Max("score"),
)
戻り値:
{
"total": 100,
"avg_score": 85.5,
"max_score": 99,
}
aggregate() は集計結果辞書を返しますが、QuerySet は返しません。
8. GROUP BYとannotate
from django.db.models import Count, Avg
| Django ORM | SQL |
|---|---|
values("city_id").annotate(total=Count("id")) | GROUP BY city_id |
values("city_id").annotate(avg=Avg("score")) | 都市別の平均スコア |
annotate(total=Count("items")) | 各オブジェクトに関連付けられたレコードの数をカウントします。 |
例:
POI.objects.values("city_id").annotate(
total=Count("id"),
avg_score=Avg("score"),
)
概念的には以下に対応します。
SELECT
city_id,
COUNT(id) AS total,
AVG(score) AS avg_score
FROM poi
GROUP BY city_id;
aggregateとannotateの違い
aggregate(): クエリ結果全体の統計値を計算し、辞書を返します。annotate(): クエリ結果のオブジェクトまたはグループに計算フィールドを追加し、QuerySet を返します。
HAVING
POI.objects.values("city_id").annotate(
total=Count("id")
).filter(total__gt=10)
概念的には以下に対応します。
SELECT city_id, COUNT(id) AS total
FROM poi
GROUP BY city_id
HAVING COUNT(id) > 10;
注: values()、annotate()、および filter() の呼び出し順序は、グループ化方法と集計結果に影響を与える可能性があります。
9. JOIN: 関連クエリ
2 つの Model があるとします。
class City(models.Model):
name = models.CharField(max_length=100)
class POI(models.Model):
name = models.CharField(max_length=100)
city = models.ForeignKey(
City,
on_delete=models.CASCADE,
related_name="pois",
)
前方相関クエリ
| Django ORM | SQL / 機能 |
|---|---|
filter(city__name="Tokyo") | JOIN City とフィルター都市名 |
values("city__name") | JOIN City と都市名を取得します |
filter(city_id=1) | 外部キー ID を使用して直接クエリを実行する |
select_related("city") | JOIN および City オブジェクトの早期ロード |
たとえば:
POI.objects.filter(city__name="Tokyo")
概念的には以下に対応します。
SELECT poi.*
FROM poi
INNER JOIN city
ON poi.city_id = city.id
WHERE city.name = 'Tokyo';
逆相関クエリ
City.objects.filter(pois__name="Tokyo Tower")
related_name="pois" から City をクエリして、それに関連付けられている POI を調べます。
以下のことも可能です:
city = City.objects.get(id=1)
city.pois.all()
この都市に関連付けられているすべての POI を返します。
related_name が指定されていない場合、通常、逆関連付けマネージャーのデフォルトは poi_set で、逆クエリのフィールド名は通常 poi です。
10. select_relatedとprefetch_related
これらは、Django ORM パフォーマンスの最適化における 2 つの非常に重要な方法であり、N+1 Query 問題 を解決するために使用されます。
N+1 Query質問
pois = POI.objects.all()
for poi in pois:
print(poi.city.name)
以下のものが生成される可能性があります:
1 回 SQL:すべてクエリ POI
N 回 SQL:それぞれを個別にクエリする POI の City
POIが100個あると、最悪の場合SQLが101回実行される可能性があります。
select_related
pois = POI.objects.select_related("city")
SQL JOIN を介して、同じクエリ内の関連オブジェクトを読み込みます。
適用対象:
- ForeignKey
- OneToOneField
特徴: SQL クエリは通常 1 回だけ実行されますが、JOIN はクエリ結果の幅と複雑さを増加させる可能性があります。
prefetch_related
cities = City.objects.prefetch_related("pois")
for city in cities:
for poi in city.pois.all():
print(poi.name)
通常、SQL は 2 回実行されます。
SQL 1:クエリ City
SQL 2:バッチクエリ関連 POI
その後、Python で関係の整理が完了します。
適用対象:
- ManyToManyField
- 逆ForeignKey(1対多)
- ForeignKey
- OneToOneField
コントラスト
| 特長 | select_related | prefetch_related |
|---|---|---|
| 作業方法 | SQL JOIN | 個別にクエリを実行し、Python で相関付ける |
| SQL 回 | 通常は1回 | 通常は複数回 |
| ForeignKey | サポート | サポート |
| OneToOneField | サポート | サポート |
| ManyToManyField | サポートされていません | サポート |
| 逆ForeignKey | サポートされていません | サポート |
| 主な目的 | 単一値の関連付け | 多値の関連付け |
一般に、単一値相関では select_related を優先し、複数値相関では prefetch_related を使用することをお勧めします。
カスタムPrefetch
from django.db.models import Prefetch
cities = City.objects.prefetch_related(
Prefetch(
"pois",
queryset=POI.objects.filter(score__gte=80),
to_attr="high_score_pois",
)
)
このようにして、条件を満たす POI のみをプリロードしてカスタム属性 high_score_pois に保存できます。
11. F式
from django.db.models import F
F を使用すると、フィールド間の計算や比較のためにデータベース内でフィールド値を直接参照できます。
更新フィールド
Product.objects.filter(id=1).update(
stock=F("stock") - 1
)
以下に対応します:
UPDATE product
SET stock = stock - 1
WHERE id = 1;
フィールド間の比較
Product.objects.filter(
sale_price__lt=F("original_price")
)
以下に対応します:
WHERE sale_price < original_price
F を使用する理由
伝統的な書き方:
product = Product.objects.get(id=1)
product.stock -= 1
product.save()
これは最初に読み取られ、次に変更され、次に書き込みが行われます。
複数のリクエストが同時に実行されると、更新が失われる問題が発生する可能性があります。
F() を使用すると、データベースがフィールド計算を直接実行できるようになり、前述の単純な読み取り変更モードによって引き起こされる競合状態が回避されます。
ただし、すべての同時実行制御メカニズムを置き換えることはできません。たとえば、複雑な在庫控除では、更新条件と影響を受ける行の数も確認する必要があります。
12. Case / When 条件式
from django.db.models import Case, When, Value, CharField
SQL の CASE WHEN に似ています。
POI.objects.annotate(
level=Case(
When(score__gte=90, then=Value("high")),
When(score__gte=60, then=Value("medium")),
default=Value("low"),
output_field=CharField(),
)
)
概念的には以下に対応します。
CASE
WHEN score >= 90 THEN 'high'
WHEN score >= 60 THEN 'medium'
ELSE 'low'
END
動的分類、条件付き並べ替え、統計的グループ化、その他のシナリオに適しています。
13. SubqueryとOuterRef
from django.db.models import Subquery, OuterRef
Django ORM で相関サブクエリを構築できるようにします。
各都市に複数の POI があると仮定すると、各都市で最高スコアの POI 名を取得する必要があります。
top_poi = POI.objects.filter(
city_id=OuterRef("pk")
).order_by("-score", "id")
cities = City.objects.annotate(
top_poi_name=Subquery(
top_poi.values("name")[:1]
)
)
2 つの中心的な概念:
Subquery(): QuerySet を SQL サブクエリとして使用します。OuterRef(): 外部クエリ内のフィールドを参照します。
ここでの OuterRef("pk") は、外側の City クエリを参照する主キーを表します。
SQL に似ています:
SELECT
city.*,
(
SELECT name
FROM poi
WHERE poi.city_id = city.id
ORDER BY score DESC, id ASC
LIMIT 1
) AS top_poi_name
FROM city;
各グループの最新レコード、各グループの最高スコア、および関連するサブクエリの処理に適しています。
14. Exists式
from django.db.models import Exists, OuterRef
たとえば、少なくとも 1 つの POI を持つ都市をクエリします。
pois = POI.objects.filter(
city_id=OuterRef("pk")
)
cities = City.objects.filter(
Exists(pois)
)
概念的には以下に対応します。
SELECT *
FROM city
WHERE EXISTS (
SELECT 1
FROM poi
WHERE poi.city_id = city.id
);
Exists は、関連オブジェクトのフィールドを実際に返さずに、関連レコードが存在するかどうかを判断するのに適しています。
15. JSONFieldクエリ
仮定:
name_translations = models.JSONField(default=dict)
データベースの内容:
{
"en": "Tokyo",
"zh": "東京",
"ja": "東京"
}
よくある質問:
| Django ORM | 意味 |
|---|---|
filter(name_translations__en="Tokyo") | en キーの値は Tokyo に等しい |
filter(name_translations__en__icontains="tok") | en キーの値には、大文字と小文字を区別せずに tok が含まれます。 |
filter(name_translations__has_key="en") | en キーは存在しますか? |
filter(name_translations__contains={"en":"Tokyo"}) | JSON には、指定されたキーと値のペアが含まれます |
注:
name_translations__enは、単純な SQL JOIN ではなく、JSON キーパス ルックアップです。- JSON クエリの SQL 実装は、特定のデータベースに依存します。
- JSONField の
containsなどの操作は、すべてのデータベース バックエンドでサポートされているわけではありません。たとえば、SQLite は JSONField のcontainslookup をサポートしません。 - 動的 JSON キーに対して大規模なクエリを実行する場合は、データベースのインデックスとクエリのパフォーマンスに注意を払う必要があります。
16. exists / count / len
| Django ORM | 機能 |
|---|---|
.exists() | QuerySet にレコードがあるかどうかを確認する |
.count() | 統計レコード数 |
len(queryset) | 結果のロード中に評価された結果の数を取得します |
.first() | 最初のレコードを取得する |
POI.objects.filter(score__gte=80).exists()
通常、次のようなものが生成されます。
SELECT 1
FROM poi
WHERE score >= 80
LIMIT 1;
大きな QuerySet がまだロードされていない場合:
- 存在するかどうかのみを判断します。通常は
exists()を使用します。 - 数量のみが必要です。通常は
count()が使用されます。 - すべてのレコードを走査する必要があります。不要なクエリの繰り返しを避けるために、QuerySet を直接走査できます。
注: QuerySet が完全に評価され、結果がキャッシュされた場合、SQL を再度実行することなく、len(queryset) はキャッシュを直接利用できます。
17. CREATE / UPDATE / DELETE
作成する
| Django ORM | SQL |
|---|---|
Model.objects.create(name="A") | INSERT INTO table ... |
obj.save() | オブジェクトのステータスに応じて INSERT または UPDATE を実行します |
get_or_create(...) | クエリ、存在しない場合は作成 |
update_or_create(...) | クエリと作成または更新 |
obj, created = Model.objects.get_or_create(
name="Tokyo",
defaults={"score": 80},
)
created は、この呼び出しによって新しいオブジェクトが作成されるかどうかを示します。
実際の使用では、重複レコードが同時に作成されるリスクを軽減するために、データベースの一意制約を通じて get_or_create() に対応する検索フィールドの一意性を確保することをお勧めします。
更新する
Model.objects.filter(id=1).update(name="A")
以下に対応します:
UPDATE table
SET name = 'A'
WHERE id = 1;
update() はデータベース レベルの更新を直接実行し、Model の save() メソッドを呼び出しず、pre_save および post_save 信号をトリガーしません。
削除
Model.objects.filter(id=1).delete()
概念的には以下に対応します。
DELETE FROM table
WHERE id = 1;
ただし、Django が関連データを削除する場合、on_delete 構成に基づいて追加のクエリと削除操作が実行される可能性があることに注意してください。
18. バッチ操作
bulk_create
POI.objects.bulk_create([
POI(name="A", city_id=1),
POI(name="B", city_id=1),
POI(name="C", city_id=2),
])
通常、バッチでデータを挿入する方が、ループで create() を呼び出すよりも効率的です。
bulk_update
pois = list(POI.objects.filter(id__in=[1, 2]))
for poi in pois:
poi.score = 90
POI.objects.bulk_update(
pois,
["score"],
)
指定されたフィールドをバッチで更新します。
注: bulk_create() および bulk_update() は、オブジェクトごとに save() を呼び出したり、対応するモデル保存信号をトリガーしたりしません。
大量のデータの場合は、batch_size を使用して各バッチ操作のサイズを制御できます。
19. トランザクション Transaction
from django.db import transaction
トランザクションは、複数のデータベース操作が全体として確実に実行されるようにするために使用されます。
atomic
with transaction.atomic():
Order.objects.create(...)
Product.objects.filter(id=1).update(
stock=F("stock") - 1
)
トランザクション内で例外が発生し、トランザクションがロールバックされる場合、データベースの変更は全体としてロールバックされます。
典型的なアプリケーション シナリオ:
- 注文を作成し、在庫を差し引きます。
- 転送操作。
- 複数のビジネス関連のデータ テーブルを同時に更新します。
select_for_update
with transaction.atomic():
product = Product.objects.select_for_update().get(
id=1
)
if product.stock > 0:
product.stock -= 1
product.save(update_fields=["stock"])
select_for_update() は、通常はトランザクションの終了まで、サポートされているデータベース内の選択されたレコードに行レベルのロックを追加します。
データを読み込んで条件を判断し、修正する必要がある兼業業務に適しています。
注: 特定のロック動作は、データベース バックエンドとトランザクション分離レベルによって異なります。 SQLite は、通常の意味での SELECT ... FOR UPDATE 行ロックをサポートしません。
20. QuerySet 遅延実行とキャッシュ
Django QuerySet の重要な特徴は、Lazy Evaluation (遅延評価) であることです。
たとえば:
qs = POI.objects.filter(score__gte=80)
これは通常、QuerySet をビルドするだけで、実際には SQL を実行しません。
実行:
for poi in qs:
print(poi.name)
その後初めて、データベースが実際にアクセスされます。
クエリをトリガーする一般的な操作
- QuerySetをトラバースします。
list()に変換します。len()を使用してください。bool()を使用してください。- まだ評価されていない QuerySet のインデックスにアクセスします。
get()、count()、exists()などのメソッドを使用して、データベース クエリを実行します。
QuerySet 結果キャッシュ
qs = POI.objects.all()
list(qs) # 実行する SQL,そして満たす QuerySet 結果のキャッシュ
list(qs) # 通常はキャッシュを再利用します
しかし、QuerySet を再構築すると、次のようになります。
POI.objects.all()
POI.objects.all()
これらは異なる QuerySet であり、結果キャッシュを自動的に共有しません。
iterator
for poi in POI.objects.iterator(chunk_size=2000):
process(poi)
iterator() は大量のデータの処理に適しており、QuerySet レベルでの完全な結果キャッシュの使用を回避します。
これは、データベース ドライバーがデータを行ごとに取得する必要があるという意味ではないことに注意してください。実際のメモリとデータ取得方法は、データベース バックエンドとカーソルの動作にも依存します。
21. クエリパフォーマンスの最適化
1. N+1 クエリを解く
POI.objects.select_related("city")
または:
City.objects.prefetch_related("pois")
2. 不要なフィールドのクエリを避ける
POI.objects.values("id", "name")
3. exists は、存在するかどうかを判断するためにのみ使用します。
POI.objects.filter(name="Tokyo").exists()
4. Python トラバーサルの代わりにデータベース集約を使用する
推奨されない:
total = len(list(POI.objects.all()))
通常は、次の方が適切です。
total = POI.objects.count()
5. データベースインデックスを適切に設定する
class POI(models.Model):
name = models.CharField(max_length=100)
score = models.IntegerField()
class Meta:
indexes = [
models.Index(fields=["name"]),
models.Index(fields=["-score"]),
]
インデックスを使用すると、修飾されたクエリを高速化できますが、ストレージ スペースと書き込みメンテナンス コストも増加します。
通常の B-tree インデックスの場合、icontains の前後のワイルドカード クエリではインデックスを効果的に使用できない可能性があります。
6. explain を使用して実行計画を分析します
qs = POI.objects.filter(score__gte=80)
print(qs.explain())
explain() は、データベース クエリの実行計画を取得し、判断を支援するために使用されます。
- インデックスを使用するかどうか。
- フルテーブルスキャンを実行するかどうか。
- JOIN はコストが高くなりますか?
- フィルタリング条件またはソート条件を最適化する必要があるかどうか。
サポートされる explain() オプションはデータベース固有です。 [分析の実行] クラス オプションを使用する場合は、実際にクエリが実行される可能性があることに注意してください。
22. その他の一般的に使用される方法
| ORM方式 | 機能 |
|---|---|
distinct() | 重複を削除する |
reverse() | 既存の並べ替えを元に戻す |
union() | 2 つのクエリ結果セットをマージする |
intersection() | 結果セットの共通部分を取得する |
difference() | 結果セットの差分を取得する |
in_bulk() | フィールド値に基づいてオブジェクト ディクショナリをバッチで取得する |
latest("created_at") | フィールドごとに最新のレコードを取得する |
earliest("created_at") | フィールドごとに最も古いレコードを取得する |
select_for_update() | レコードのクエリとロック |
using("default") | データベース接続の指定 |
raw() | ネイティブ SQL クエリを実行し、モデル インスタンスを返します。 |
union(), intersection(), and difference() correspond to the SQL set operation, and there are restrictions on field compatibility, sorting, and slicing operations.
23. Django ORMとSQLの関係
Django ORM は、SQL の代替データベースではなく、SQL が構築される高レベルの抽象化です。
全体的なワークフロー:
Python ORM
↓
QuerySet 構築する
↓
SQL Compiler
↓
SQL + Parameters
↓
データベース主導型
↓
PostgreSQL / MySQL / SQLite
↓
クエリ結果
↓
Model / Dict / Tuple
QuerySet によって生成された SQL を表示するには、次の方法を使用できます。
qs = POI.objects.filter(
score__gte=80
).order_by("-score")
print(qs.query)
str(qs.query) はデバッグには適していますが、安全に再実行できるパラメータ化された SQL として直接受け取るべきではありません。
SQL とパラメータを表示する必要がある場合は、次を使用できます。
sql, params = qs.query.sql_with_params()
In actual operation, Django uses the database-driven parameterized query mechanism to process variables to avoid splicing ordinary parameters directly into the SQL string.
概要
Django ORM 学習の焦点は 4 つのレベルに分けることができます。
| レベル | フォーカス |
|---|---|
| 基本操作 | filter、get、exclude、values、order_by |
| SQL クエリ機能 | Q、F、annotate、aggregate、JOIN、Subquery |
| データ操作 | create、update、delete、bulk_create、transaction |
| パフォーマンスの最適化 | select_related、prefetch_related、インデックス、explain、QuerySet キャッシュ |
毎日の Django バックエンド開発では、filter()、Q()、F()、annotate()、select_related()、および prefetch_related() に精通していることが優先されます。
より複雑なデータ処理については、Subquery()、OuterRef()、Exists()、トランザクション、データベース ロック メカニズムについて詳しく学習してください。
Django ORM は多くの一般的なデータベース操作をカバーできますが、効率的で信頼性の高いクエリを作成するには、SQL、インデックス、JOIN、トランザクション、およびデータベース実行プランを理解する必要があります。
参考資料: