6

我想使用 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()

现在,我想使用 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))

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

4

6 回答 6

6

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)
)
于 2017-08-01T22:05:33.720 回答
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 回答
3

如果我理解正确,您将花费从现在到数据库中的值的最长时间。

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

from django.db.models import F
MyData.objects.filter(pk=dataID).update(targetTime=max(F('targetTime'),timezone.now()) + timedelta(days=XX))
于 2013-06-17T19:47:47.967 回答
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(可以通过F) 来实现,但至少这可以让您进行一次插入/更新。

于 2013-06-18T01:48:52.183 回答
0

我已经想出了如何使用原始 SQL 语句来做到这一点:

cursor = connection.cursor()
cursor.execute("UPDATE `mydatabase_name` SET `targetTime` = CASE WHEN `targetTime` < %s THEN %s ELSE (`targetTime` + %s) END WHERE `dataID` = %s", [timezone.now(), timezone.now() + timedelta(days=XX), timedelta(days=XX), dataID])
transaction.commit_unless_managed()

我现在正在使用它,它似乎正在完成我想要的。

于 2013-06-18T17:03:03.333 回答
0

简单示例:

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"),))
于 2021-12-29T09:27:09.593 回答