【问题标题】:Increment Page Hit Count in Django在 Django 中增加页面点击计数
【发布时间】:2009-03-07 22:42:05
【问题描述】:

我有一个带有IntegerField (hit_count) 的表,当访问一个页面时(例如http://site/page/3),我希望数据库中记录ID 3 的hit_count 列增加1。

查询应该是这样的:

update table set hit_count = hit_count + 1 where id = 3

我可以使用标准的 Django 模型约定来做到这一点吗?还是我应该手动编写查询?

【问题讨论】:

标签: python django django-models


【解决方案1】:

如果你使用 Django 1.1+,只需使用F expressions:

from django.db.models import F
...
MyModel.objects.filter(id=...).update(hit_count=F('hit_count')+1)

这将执行单个原子数据库查询。

正如 gerdemb 所说,您应该考虑将其放在中间件中,以使其易于重用,这样就不会弄乱您的所有视图。


【讨论】:

  • 谢谢 - 打算链接到那个但忘记了。我会添加它。
  • 我认为你想要的是MyModel.objects.get(id=...),而不是filter;如果我们知道它是单行,为什么不说清楚呢?
  • @Jared 因为 .get() 不是惰性的(它实际上是查询数据库)。这就是为什么单个模型对象没有 .update() 方法的原因;一旦您已经查询过,您只需使用 .save()。但是你会失去原子性,这就是这里的重点。用于原子更新的 .update() 方法仅在 QuerySets 上可用,并且只有因为它们是惰性的才可能。
  • 哦,这很有趣。谢谢。
【解决方案2】:

正如 gerdemb 所说,您应该将其写入中间件以使其真正可重用。或者(更简单)编写一个函数装饰器。事实上,有一些适配器可以将中间件用作装饰器,反之亦然。

但如果您担心性能并希望保持每页的数据库查询命中率较低,您可以使用 memcached 的原子增量操作。当然,在这种情况下,你必须自己照顾持久性。

【讨论】:

  • 为了获得良好的性能,memcached 解决方案是迄今为止最好的,但它更复杂。
【解决方案3】:

模型约定不是原子的;手写:

BEGIN
SELECT * FROM table WHERE id=3 FOR UPDATE
UPDATE table SET hit_count=hit_count+1 WHERE id=3
COMMIT

【讨论】:

  • Django 的 ORM 支持这个查询(在trunk中,很快 v1.1 中)——你不需要手动编写。
【解决方案4】:

我将首先查看middleware 的文档。 Ignacio 关于缺乏原子事务的评论是真实的,但这是整个 Django 框架的问题。除非您担心拥有 100% 准确的计数器,否则我不会担心。

【讨论】:

  • 这是一个“整个 Django 框架的问题”?您可以使用 TransactionMiddleware 对每个请求进行原子事务,或者使用 django.db.transaction 中的函数进行更细粒度的控制。
  • 当然可以有事务,但默认情况下是不启用的。如果您使用内置的 Django 管理员构建一个简单的 CRUD 应用程序,您将遇到竞争条件。即使是 Django 文档中的教程也存在这类问题。
  • 你的措辞让它听起来像是一个不可避免的问题,这当然会误导那些可能不像你那么了解 Django 的人。
猜你喜欢
  • 1970-01-01
  • 2012-03-04
  • 2020-04-30
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多