サーチ…


前書き

F()式は、DjangoがPythonオブジェクトを使用して、データベースのモデルフィールドや注釈付きの列の値をPythonメモリにプルする必要なく参照する方法です。これにより、開発者は特定のレース条件を回避し、モデルフィールド値に基づいて結果をフィルタリングすることができます。

構文

  • django.db.modelsからのインポートF

競合状態の回避

競合状況がわからない場合は、 このQ&Aの質問を参照してください。

次のコードは競合条件の対象となる場合があります。

article = Article.objects.get(pk=69)
article.views_count += 1
article.save()

views_count1337に等しい場合、このようなクエリが発生します。

UPDATE app_article SET views_count = 1338 WHERE id=69

2つのクライアントが同時にこの記事にアクセスした場合、何が起こることがあり、第2のHTTPリクエストが実行されるということですArticle.objects.get(pk=69)最初に実行する前にarticle.save() 。したがって、両方の要求はviews_count = 1337を持ち、増分してviews_count = 1338をデータベースに保存しますが、実際には1339です。

これを修正するには、 F()式を使用します。

article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()

一方、これはそのようなクエリになります:

UPDATE app_article SET views_count = views_count + 1 WHERE id=69

クエリーセットの一括更新

id 51著者のすべての記事から2つのアップフォォートを削除したいとしましょう。
これをPythonでのみ行うと、 Nクエリが実行されます( Nはクエリセット内のアーティクルの数です)。

for article in Article.objects.filter(author_id=51):
    article.upvotes -= 2
    article.save()
    # Note that there is a race condition here but this is not the focus
    # of this example.

もし全ての記事をPythonに引っ張ってループしたり、アップボントを減らしたり、更新された記事をデータベースに保存したりするのではなく、別の方法がありましたか?
F()式を使用すると、1つのクエリでそれを実行できます。

Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)

これは、次のSQLクエリで翻訳できます。

UPDATE app_article SET upvotes = upvotes - 2 WHERE author_id = 51

なぜこれは良いですか?

  • Pythonが作業を行う代わりに、データベースに負荷を渡します。この負荷は、そのようなクエリを行うために微調整されています。
  • 必要な結果を得るために必要なデータベースクエリの数を効果的に削減します。

フィールド間の算術演算を実行する

F()式を使用して、モデルフィールド間の代数ルックアップ/接続を定義するために、モデルフィールド間の算術演算( +-*など)を実行できます。

  • モデルを次のようにします。

    class MyModel(models.Model):
        int_1 = models.IntegerField()
        int_2 = models.IntegerField()
    
  • ここで、 int_1int_2フィールドがこの式を満たすMyModelテーブルのすべてのオブジェクトを取得すると仮定しますint_1 + int_2 >= 5annotate()filter()を利用すると、次のようになります。

    result = MyModel.objects.annotate(
                 diff=F(int_1) + F(int_2)
             ).filter(diff__gte=5)
    

    resultには前述のすべてのオブジェクトが含まれるようになりました。

この例ではIntegerフィールドを使用していますが、このメソッドは算術演算を適用できるすべてのフィールドで機能します。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow