ORM

Django ORMのupdate入門|データを更新する方法

Django ORM

Django ORMのupdate入門
データを更新する方法

Django ORMでデータベースのレコードを更新する方法を解説します。save()による単一更新からupdate()による一括更新まで紹介します。

こんな人向けの記事です

  • Django ORMでデータの更新方法を学びたい人
  • save()とupdate()の違いを理解したい人
  • 一括更新やF式を活用したい人

Step 1save()で1件更新

モデルインスタンスのフィールドを変更してsave()を呼ぶと、データベースが更新されます。

Python
# models.py
from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=200)
    price = models.IntegerField()
    stock = models.IntegerField(default=0)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.name
Python
# 1件取得してフィールドを変更し、保存
product = Product.objects.get(id=1)
print(f"変更前: {product.price}円")

product.price = 1500
product.save()
print(f"変更後: {product.price}円")
実行結果
変更前: 1000円
変更後: 1500円
Python
# update_fieldsで更新するフィールドを限定(パフォーマンス向上)
product = Product.objects.get(id=1)
product.price = 2000
product.save(update_fields=["price"])  # priceだけUPDATEされる
update_fieldsを指定するメリット
save()はデフォルトで全フィールドをUPDATEします。update_fieldsを指定すると、指定したフィールドのみがUPDATE文に含まれるため、パフォーマンスが向上し、競合も防げます。

Step 2update()で一括更新

QuerySetのupdate()メソッドを使うと、条件に一致する複数のレコードを1回のSQLで一括更新できます。

Python
# 在庫が0の商品を非アクティブにする
updated_count = Product.objects.filter(stock=0).update(is_active=False)
print(f"{updated_count}件の商品を非アクティブにしました")

# 全商品の価格を1000円にする
Product.objects.all().update(price=1000)

# 特定条件の複数フィールドを同時に更新
Product.objects.filter(
    is_active=False
).update(
    price=0,
    stock=0
)
実行結果
3件の商品を非アクティブにしました
update()の注意点
update()はSQLを直接発行するため、モデルのsave()メソッドやシグナル(pre_save, post_save)は呼ばれません。これらの処理が必要な場合はsave()を使ってください。

Step 3F式を使った相対更新

現在の値を基準に更新したい場合は、F()式を使います。Pythonにデータを読み込まずにデータベース上で計算できます。

Python
from django.db.models import F

# 全商品の価格を10%値上げ
Product.objects.all().update(price=F("price") * 1.1)

# 在庫を1つ減らす
Product.objects.filter(id=1).update(stock=F("stock") - 1)

# 複数フィールドを相対的に更新
Product.objects.filter(is_active=True).update(
    price=F("price") + 100,
    stock=F("stock") + 10
)

# save()でもF式は使える
product = Product.objects.get(id=1)
product.stock = F("stock") + 5
product.save(update_fields=["stock"])

# 注意: F式を使った後はrefresh_from_db()が必要
product.refresh_from_db()
print(f"在庫: {product.stock}")
F式のメリット
F式を使うと、データベース側で計算が行われるため、複数のリクエストが同時にデータを更新する場合でも競合(レースコンディション)を防ぐことができます。

Step 4update_or_create()で更新または作成

条件に一致するデータがあれば更新し、なければ新規作成する場合はupdate_or_create()を使います。

Python
# nameが"りんご"のデータがあれば更新、なければ作成
product, created = Product.objects.update_or_create(
    name="りんご",                         # 検索条件
    defaults={"price": 200, "stock": 50}  # 更新/作成するフィールド
)

if created:
    print(f"新規作成: {product.name}")
else:
    print(f"更新: {product.name} → {product.price}円")

# 複数の検索条件も指定可能
product, created = Product.objects.update_or_create(
    name="りんご",
    is_active=True,
    defaults={"price": 250}
)
実行結果
更新: りんご → 200円

Step 5save()とupdate()の使い分け

状況に応じて適切な更新方法を選びましょう。

Python
# === save(): モデルの振る舞いが必要なとき ===
# ✓ save()メソッドをオーバーライドしている場合
# ✓ pre_save / post_saveシグナルが必要な場合
# ✓ バリデーションを実行したい場合
product = Product.objects.get(id=1)
product.price = 2000
product.full_clean()  # バリデーション実行
product.save()

# === update(): 高速な一括更新 ===
# ✓ 大量のレコードを更新する場合
# ✓ シグナルやバリデーションが不要な場合
# ✓ パフォーマンスを重視する場合
Product.objects.filter(is_active=False).update(stock=0)

# === bulk_update(): save()の動作で複数件更新 ===
products = list(Product.objects.filter(is_active=True))
for p in products:
    p.price = int(p.price * 1.1)

Product.objects.bulk_update(products, ["price"])
# bulk_update()はSQLをまとめるが、シグナルは呼ばれない

まとめ

  • save()はインスタンスを変更後に保存する基本的な更新方法
  • update()はQuerySetで条件を指定して一括更新できる(高速)
  • F()式を使うとデータベース上で相対的な値の更新ができる
  • update_or_create()で「あれば更新、なければ作成」が1行で書ける
  • update()はsave()やシグナルを呼ばないため、用途に応じて使い分ける