説明されるDangango ORM:選択されたCount関連とprefetchchen関連


Django ORMでの作業はSQL文を記述せずにデータベースからデータを検索する方法を提供します.しかし、SQL文の代わりにORMを使用すると、パフォーマンス低下が確実になりますが、大部分のCRUDアプリケーションでは、役に立たないデータベースクエリーを減らして、あなたのDjangoアプリケーションをより速くする方法を探しているまで、それは意味がありません.

パフォーマンス問題の例


このモデルの例を挙げましょう.
from django.db import models


class User(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=254)


class Profile(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=50)
すごい!ここに2つのモデルがありますProfile モデルはForeignKey -- 一つから多くへUser モデルは、ユーザーが多くのプロファイルを持つことができることを意味します.
プロファイルオブジェクトを持っているなら、ユーザを得るデフォルトの方法は何ですか?
# hit the database
profile = Profile.objects.first()

# hit the database again to get the related User object
user = profile.user
さて、我々はちょうどここで2つの質問をしました.かなり大きな問題ではありませんが、これらの行を最適化し、不要な問い合わせを避ける必要があります.

選択


からDjango docs , select_related() 外部キー関係を「フォローします」というクエリを返します.これは、単一のより複雑なクエリをもたらすパフォーマンスのブースターですが、その後の外部キー関係の使用はデータベースクエリを必要としません.
基本的にはselect_related 選択したいオブジェクトが単一のオブジェクトである場合、OneToOneField またはForeignKey .
フェッチする行を書き直しましょうuser を持つprofile オブジェクト.
# Hits the database
profile = Profile.objects.select_related('user').first()

# Doesn't hit the database, because profile.user has been prepopulated
# in the previous query.
user = profile.user
そして、我々はちょうど2つの質問を1に変えました.しかし、あなたが持っているとき、何が起こりますかManyToMany 関係ManyToOne ?
ユーザーオブジェクトを持つすべてのプロファイルを取得しなければならない場合を調べましょう.

プリフェッチ関連


ユーザーモデルにstrメソッドを追加しましょう.
class User(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=254)
    password = models.CharField(max_length=50)

    def __str__(self) -> str:
        return "%s (%s)" % (self.name,
            ", ".join(profile.first_name for profile in self.profile_set.all()))

Note: If you are using a ForeignKey relationship in Django between an M1 model and an M2 model -- which is symmetrical by default --, the M1 model has automatically a reverse relationship field of type ManyToOne.


次のコードを実行すると、次の結果が得られます.
>>> User.objects.all()
[<User: User (John Doe)>, <User: User (Jane Doe)> ...]
この質問の問題は、毎回__str__ ユーザーモデルのメソッドをコールします.self.profile_set.all() .
そして、クエリの数は、ユーザーによるプロファイルの数に比例しています:よく、悪夢.🥶
しかし、どのように我々はちょうど2つの質問にこれを減らすことができますか?まあ、使用prefetch_related .
User.objects.prefetch_related('profile_set').all()
使用するprefetch_related あなたが物事の「セット」を得るつもりであるときManyToMany または逆ForeignKey -- ManyToOne .

次に、2つの違いは何ですか?


どちらも、データベースからデータをプリフェッチするのと同じ原理で動作しますが、それらは異なるアプローチを行います.
すでに以下に述べましたが、この内容について結論を出しましょう.
  • 使用するselect_related 選択したいオブジェクトが単一のオブジェクトである場合、OneToOneField またはForeignKey .
  • 使用するprefetch_related あなたが物事の「セット」を得るつもりであるときManyToMany または逆ForeignKey -- ManyToOne .
  • ただし、これらのメソッドを使用する必要があります場合は、データベースのクエリ番号を削減し、データベースからのデータのより大きなサイズを取得する問題はありません.
    私の経験では、これらのメソッドは本当にJjangoで空腹のcronジョブを実行するのに役に立ちました.🤟‍
    Djangoアプリケーションでのデータベースクエリーを少なくするために、他の方法を使用しますか?コメント欄で議論しましょう.
    記事投稿bloggu.io . 無料でお試しください.