6

Django を使用して、現在の値に応じてフィールドを別の値に更新したいのですが、2 つの個別の update ステートメントを実行せずにそれを行う方法がわかりません。

これが私がやりたいことの例です:

now = timezone.now()
data = MyData.objects.get(pk=dataID)
if data.targetTime < now:
    data.targetTime = now + timedelta(days=XX)
else:
    data.targetTime = data.targetTime + timedelta(days=XX)
data.save()

今、update() ステートメントを使用して、データの他のフィールドを上書きしないようにしたいのですが、1 つの update() でそれを行う方法がわかりません。このようなコードをいくつか試しましたが、2 回目の更新では最新の時刻が使用されませんでした (最終的に現在の時刻に等しいフィールドになりました)。

# Update the time to the current time
now = timezone.now()
MyData.objects.filter(pk=dataID).filter(targetTime__lt=now).update(targetTime=now)
# Then add the additional time
MyData.objects.filter(pk=dataID).update(targetTime=F('targetTime') + timedelta(days=XX))

これを単一の update() ステートメントに減らす方法はありますか? SQL CASE ステートメントに似たものはありますか?

4

6 に答える 6

5

このように条件式を使用する必要があります

from django.db.models import Case, When, F

object = MyData.objects.get(pk=dataID)
now = timezone.now()
object.targetTime = Case(
    When(targetTime__lt=now, then=now + timedelta(days=XX)),
    default=F('targetTime') + timedelta(days=XX)
)
object.save(update_fields=['targetTime'])

デバッグのために、これを直後に実行しsaveて、実行したばかりの SQL クエリを確認してください。

import pprint
from django.db import connection
pprint.pprint(["queries", connection.queries])

これを整数でテストしましたが、Django 1.8 で動作します。日付はまだ試していないので、微調整が必​​要かもしれません。

于 2016-01-28T17:40:06.670 に答える
2

queryset.update(...)を使用する代わりに、既存のフィールドを上書きしないobj.save(update_fields=['field_one', 'field_two'])( https://docs.djangoproject.com/en/dev/ref/models/instances/#specifying-which-fields-to-saveを参照) を使用します。

最初に選択クエリなしでこれを行うことはできません ( get)。条件に基づいて 2 つの異なることを行っているためです (つまり、Django を使用してそのようなロジックをデータベースに渡すことはできません。できることには制限があります)。 )で実現Fできますが、少なくともこれにより、単一の挿入/更新が得られます。

于 2013-06-18T01:48:52.183 に答える