如何在有条件的情况下进行 Django 更新?

cam*_*ilk 6 django

我想使用 Django 根据其当前值将字段更新为不同的值,但我不知道如何在不执行 2 个单独的更新语句的情况下执行此操作。

这是我想做的一个例子:

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()
Run Code Online (Sandbox Code Playgroud)

现在,我想使用 update() 语句来避免覆盖数据上的其他字段,但我不知道如何在单个 update() 中执行此操作。我尝试了一些这样的代码,但第二次更新没有使用最新时间(我最终得到了一个等于当前时间的字段):

# 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))
Run Code Online (Sandbox Code Playgroud)

有没有办法可以将其简化为单个 update() 语句?类似于 SQL CASE 语句的东西?

Fli*_*imm 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'])
Run Code Online (Sandbox Code Playgroud)

对于调试,请尝试立即运行此命令save以查看刚刚运行的 SQL 查询:

import pprint
from django.db import connection
pprint.pprint(["queries", connection.queries])
Run Code Online (Sandbox Code Playgroud)

我已经用整数测试过它并且它在 Django 1.8 中工作,我还没有尝试过日期,所以它可能需要一些调整。


whp*_*whp 5

Django 1.9 添加了 Greatest 和 Least数据库函数。这是Benjamin Toueg回答的改编版:

from django.db.models import F
from django.db.models.functions import Greatest


MyData.objects.filter(pk=dataID).update(
    targetTime=Greatest(F('targetTime'), timezone.now()) + timedelta(days=XX)
)
Run Code Online (Sandbox Code Playgroud)


Dee*_*hta 5

Django 3 及以上版本的简单示例:

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

MyModel.objects.filter(abc__id=abc_id_list)\
                .update(status=Case(
                    When(xyz__isnull=False, then=Value("this_value")),
                    default=Value("default_value"),))
Run Code Online (Sandbox Code Playgroud)


Ben*_*ueg 3

如果我理解正确的话,你需要从现在到数据库中的值之间的最长时间。

如果是这样,您可以使用 max 函数在一行中完成此操作:

from django.db.models import F
MyData.objects.filter(pk=dataID).update(targetTime=max(F('targetTime'),timezone.now()) + timedelta(days=XX))
Run Code Online (Sandbox Code Playgroud)