ORM

Django ORMでフィールドの値を使った演算|F式の使い方

DjangoのORMで、データベース上のフィールドの値を直接参照して演算を行うには、F式(Fオブジェクト)を使用します。Pythonにデータを読み込まずにデータベース側で計算を完結させるため、効率的な処理が可能です。

基本的な使い方

views.py
update_model = Sales.objects.update(sale = F('sale')*1.1)

説明

Step 1F式の基本

Djangoでは、F式を使用してデータベースレベルでフィールド値に対する計算を行うことができます。基本的な構文は以下の通りです:

from django.db.models import F

F('フィールド名')計算式

このF式を使用すると、Pythonレベルではなくデータベースレベルでの操作が可能になり、効率的なデータ更新ができます。

Step 2基本的な使用例

例えば、Salesモデルのsaleフィールドの値を1.1倍(10%増)する場合:

from django.db.models import F

# Salesモデルのsaleフィールドを全て1.1倍する
Sales.objects.update(sale=F('sale') * 1.1)

上の例は、Salesモデルのsaleフィールドを全て1.1倍した値にして更新しています。

Step 3様々な計算例

F式では様々な計算が可能です:

# 加算
Product.objects.update(price=F('price') + 100)  # 価格を100円上げる

# 減算
Product.objects.update(price=F('price') - 50)  # 価格を50円下げる

# 乗算
Product.objects.update(price=F('price') * 1.05)  # 価格を5%上げる

# 除算
Product.objects.update(price=F('price') / 2)  # 価格を半額にする

# べき乗
Product.objects.update(price=F('price') ** 2)  # 価格を2乗する

Step 4条件付き更新

特定の条件に一致するレコードだけを更新することもできます:

# 価格が1000円以上の商品のみ10%割引
Product.objects.filter(price__gte=1000).update(price=F('price') * 0.9)

# 在庫が10個未満の商品の在庫を2倍にする
Product.objects.filter(stock__lt=10).update(stock=F('stock') * 2)

Step 5複数フィールドの計算

F式を使って別のフィールドを参照した計算も可能です:

# 単価と数量から合計金額を計算
Order.objects.update(total_amount=F('unit_price') * F('quantity'))

# 在庫と予約数から利用可能数を計算
Product.objects.update(available=F('stock') - F('reserved'))

Step 6実践的な使用例

views.pyでのF式の使用例:

from django.shortcuts import redirect
from django.contrib import messages
from django.db.models import F
from .models import Product

def apply_discount(request):
    # 割引率を取得(デフォルトは10%)
    discount_rate = float(request.POST.get('discount_rate', 10)) / 100
    category_id = request.POST.get('category_id')
    
    # 基本クエリ
    query = Product.objects
    
    # カテゴリが指定されている場合はフィルタリング
    if category_id:
        query = query.filter(category_id=category_id)
    
    # 価格を割引率に基づいて更新
    updated_count = query.update(price=F('price') * (1 - discount_rate))
    
    messages.success(request, f"{updated_count}件の商品に{int(discount_rate*100)}%の割引を適用しました")
    return redirect('product_list')

def increment_view_count(request, product_id):
    # 商品の閲覧数を1増やす
    Product.objects.filter(id=product_id).update(view_count=F('view_count') + 1)
    
    # 商品詳細ページにリダイレクト
    return redirect('product_detail', product_id=product_id)
F式のメリット:
  • データベースレベルで計算が行われるため、Python側でデータを取得して計算するよりも効率的です。
  • 複数のユーザーが同時に更新した場合でも、競合状態(race condition)を回避できます。
  • 大量のレコードを一度に更新する場合、メモリ使用量が少なくて済みます。

まとめ

  • F式を使うとデータベース側でフィールドの値を直接参照・演算できる
  • update()と組み合わせて、値の増減などをSQL1文で実行できる
  • レースコンディション(競合状態)を防ぐ効果がある
  • filter()内でフィールド同士の比較に使用できる
  • annotate()内で計算フィールドを追加する際にも活用できる
  • from django.db.models import Fでインポートして使用する