Django数据库模型F组合表达式

10
In [1]: from django.db.models import F

In [2]: from forum.models import Post

In [3]: post = Post.objects.get(id=1)

In [4]: post.view_count = F('view_count') + 1

In [5]: post.save()

In [6]: post.view_count

Out[6]: <CombinedExpression: F(view_count) + Value(1)>

In [7]: post = Post.objects.get(id=1)

In [8]: post.view_count

Out[8]: 3

保存文章后,它返回了合并的表达式。

我想要确切的结果(3)。

不调用get方法或refresh_from_db方法,这是否可能做到?

3个回答

15
在Django 1.8+中,您可以使用refresh_from_db方法。它不会保存任何SQL查询,但您可能会认为代码更加清晰易懂。
>>> post = Post.objects.get(id=1)
>>> post.view_count
2
>>> post.view_count = F('view_count') + 1
>>> post.save()
>>> post.refresh_from_db()
>>> post.view_count
3

由于更新发生在数据库中,在Django中不可能获取新值而不进行get()refresh_from_db(两者都会导致类似的SQL查询)。但是,可以通过使用update()来避免初始get()

>>> Post.objects.filter(id=1).update(view_count=F('view_count') + 1)
>>> post = Post.objects.get(id=1)
>>> post.view_count
3

谢谢,刷新或重新加载数据库模型需要时间吗?我使用的代码如下: post.refresh_from_db(fields=['view_count',]) - Muthuvel
我不确定你的问题是什么。你想知道执行 refresh_from_db() 还是 get() 会花费更长的时间吗? - Alasdair
不,我并不是在比较get()和refresh_from_db()。通常情况下,一次会有1万个用户更新值,那么视图计数的响应速度是缓慢还是正常的? - Muthuvel
你需要进行一些性能测试,我不知道在10K用户下它的表现如何。 - Alasdair

1

从文档中了解到https://docs.djangoproject.com/en/1.7/ref/models/queries/#f-expressions,

Python不会知道封装的SQL表达式post.view_count = F('view_count') + 1 # F('view_count') Django sql expression

它完全由数据库处理。

因此,在Python中进行更改时,所有已应用表达式的内容都是已知的,而不是结果。

您可以直接通过以下方式进行操作:

post = Post.objects.filter(id=1)
post.update(view_count = F('view_count') + 1) 

它会引发属性错误: AttributeError: 'Post'对象没有属性'update'。 更新将使用查询集对象列表。In [14]: post = Post.objects.filter(id=1)In [15]: post.update(view_count = F('view_count') + 1) Out[15]: 1In [16]: post[0].view_count Out[16]: 5 - Muthuvel
@Muthuvel 谢谢,我在更新queryset时出错了。 - Vishnu Upadhyay

-4
为什么不直接写 post.view_count += 1 呢?

如果我们使用F(),可以让数据库而非Python来完成工作,并减少某些操作所需的查询次数。 - Muthuvel
但是既然你想要实际获取值,使用 F 没有意义。 - Nhor
如果我们使用F(),就能够减少查询时间。这是正确的吗? - Muthuvel
如果您只想获取一个项目,那么没有区别,唯一的区别在于内存,因此它对于整个对象查询非常有用,而不仅仅是一个。 - Nhor
5
post.view_count = F('view_count') + 1 的优点在于它能够始终将值增加一。如果两个用户同时执行 post.view_count += 1 操作,那么该值可能只会被更新一次,而不是两次。 - Alasdair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接