ホームページ > バックエンド開発 > Python チュートリアル > 修正すべき Django ORM の一般的な間違い

修正すべき Django ORM の一般的な間違い

Barbara Streisand
リリース: 2025-01-04 00:49:40
オリジナル
1024 人が閲覧しました

Common Django ORM Mistakes to fix

Django ORM は、Django の最も強力な機能の 1 つです。これにより、データベースとのやり取りの複雑さの多くが抽象化され、開発者は生の SQL ではなく Python 構文を使用してデータを操作できるようになります。これらすべての ORM 関数は、慎重に処理しないとボトルネックになる可能性がある SQL クエリを生成します。
このブログでは、Django ORM を使用する際のよくある間違いを強調し、クエリの効率性、保守性、パフォーマンスを維持するためのヒントも提供します。

1. N 1 クエリの問題

N 1 クエリの問題は、コードが 1 つのクエリをトリガーして一連のレコードを取得し、その後 N 個の追加のクエリを再度実行して関連データを取得するときに発生します。

blogs = Blog.objects.all()    # 1 Query
for blog in blogs:
    print(blog.author.name)   # N additional queries
ログイン後にコピー
ログイン後にコピー

上記の例では、ループ内で blog.author.name にアクセスすると、Django が各ブログの著者レコードを個別にフェッチし、N 個の追加クエリが発生します。

修正方法
SQL JOIN を実行してメイン オブジェクトとその関連オブジェクトを 1 つのクエリで取得するため、単一の関連オブジェクト (ForeignKey や OneToOneField など) には select_popular を使用します。多対多、多対 1、または逆の関係の場合は、prefetch_relative を使用します。これにより、関連するデータが個別のクエリでフェッチされますが、それらのデータが Python で効率的に結合され、N 1 の問題が回避されます。

# With select_related
blogs = Blog.objects.select_related('author').all()

# With prefetch_related
authors = Author.objects.prefetch_related('blogs').all()
ログイン後にコピー
ログイン後にコピー

2. .all() と .filter() の過剰使用

開発者は、複数のフィルターをチェーンしたり、.all() を使用した後に同じクエリセットに対してクエリを繰り返したりすることがよくあります。

blogs = Blog.objects.all()
active_blogs = blogs.filter(is_archived=False)
popular_blogs = blogs.filter(views__gte=1000)
ログイン後にコピー
ログイン後にコピー

Django は必要な場合にのみクエリセットを遅延評価してクエリセットを最適化しようとしますが、同じクエリセット データに対してフィルターを繰り返し呼び出すと、データベースに不要なヒットが発生する可能性があります。

修正方法
フィルターを 1 つのステートメントに結合すると、django は単一の SQL クエリを生成できます。

popular_active_blogs = Blog.objects.filter(is_archived=False, views__gte=1000)
ログイン後にコピー

3.values() または value_list() を活用していない

モデルのすべてのフィールド データではなく、特定のフィールドのみが必要な場合があります。この間、.values() または .values_list() を使用すると、より効率的になります。

titles = Blog.objects.values('title')
or
titles = Blog.objects.values_list('title', flat=True)
# values() returns a list of dictionaries.
# values_list() can return tuples or flat values if flat=True is provided.
ログイン後にコピー

必要な列のみをフェッチすることで、データベースから転送されるデータ量が削減され、パフォーマンスが向上します。

4. 非効率的な集計と注釈

.aggregate() または .annotate() を繰り返し呼び出すと、複数のクエリが発生する可能性があります。複数の注釈を含む複雑なクエリは非効率的な SQL クエリにつながる可能性があり、データベース操作が重くなる可能性があります。

# Example of multiple aggregate
total_count = Blog.objects.aggregate(Count('id'))
author_count = Blog.objects.aggregate(Count('author'))
average_views = Blog.objects.aggregate(Avg('views'))
ログイン後にコピー

おすすめ

blogs = Blog.objects.all()    # 1 Query
for blog in blogs:
    print(blog.author.name)   # N additional queries
ログイン後にコピー
ログイン後にコピー

5. データベースインデックスを使用しない

インデックスを作成すると、データベースがデータを迅速に検索して取得できるようになり、低速の全テーブル スキャンが回避され、クエリのパフォーマンスが向上します。インデックスにより、フィルタリング、並べ替え、結合などの操作が最適化され、頻繁にアクセスされるフィールドに対するクエリが大幅に高速化されます。頻繁にクエリされるフィールドのデータベース インデックスが欠落していると、パフォーマンスが大幅に低下する可能性があります。
Django でインデックスを追加する方法

# With select_related
blogs = Blog.objects.select_related('author').all()

# With prefetch_related
authors = Author.objects.prefetch_related('blogs').all()
ログイン後にコピー
ログイン後にコピー

インデックスを使用すると読み取り速度は速くなりますが、書き込み速度は遅くなります。したがって、頻繁にクエリを実行する必要があるフィールドのみにインデックスを付けてください。

6. キャッシュを使用しない

計算にコストがかかるデータ、またはめったに変更されないデータをクエリする必要がある場合は、キャッシュを使用します。 5 分間でもキャッシュすると、繰り返されるクエリ、複雑な計算、および頻繁に変更されないクエリを保存できます。

blogs = Blog.objects.all()
active_blogs = blogs.filter(is_archived=False)
popular_blogs = blogs.filter(views__gte=1000)
ログイン後にコピー
ログイン後にコピー

7. 生の SQL

Django ORM は、複雑なクエリや一括操作を効率的に表現できない場合があります。 Django は .extra() または .raw() を提供しますが、次の理由から生の SQL の使用は最後の手段である必要があります。

  • ORM の利点の多くが失われます
  • コードが読めなくなったり、エラーが発生しやすくなる可能性があります

入力が適切にサニタイズされ、生の SQL クエリが保守可能に保たれるようにします。

これらのヒントを適用すると、コードをクリーンで保守しやすく保ちながら、Django アプリのパフォーマンスが向上します。また、開発環境で Django Debug Toolbar を使用して、実行されるクエリの数、実行時間、SQL ステートメントを監視および分析することも提案されています。

以上が修正すべき Django ORM の一般的な間違いの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート