【发布时间】:2014-02-06 14:32:12
【问题描述】:
我目前正在开发一款游戏,用户可以在其中获得经验值。我的(自定义)用户模型如下所示:
class TriariadUser(AbstractBaseUser, PermissionsMixin):
pseudonym = models.CharField(max_length=40)
level = models.PositiveSmallIntegerField(default=1)
experience_points = models.PositiveIntegerField(default=0)
def add_ep_points(self, points):
self.experience_points += points
if self.experience_points >= get_next_level_ep(self.level):
level += 1
self.save()
现在我有各种信号监听器,可以为用户添加体验点。问题是:如果在一个请求期间获得多个 XP,则最后一次获得的 XP 会覆盖所有其他的。
显然这是一个竞争条件,所以我尝试将我的函数修改为静态并使用select_for_update:
@staticmethod
def add_ep_points(user_id, points):
user = TriariadUser.objects.select_for_update.get(pk=user_id)
user.experience_points += points
...
这按预期工作,但是模板中的用户对象没有更新。也就是说,必须提出一个新的请求,让用户看到发生了什么。使用 django 调试工具栏我可以看到,加载用户的请求是在开始时发出的。之后进行所有相关更新。但是之后用户并没有重新加载,所以显示的是旧状态。
我可以想到各种解决方法,例如使用 JavaScript 重新加载,但必须有一些其他解决方案(至少我希望如此)。
有没有办法在 django 中锁定对象?有没有办法告诉一个对象需要重新加载?有没有更好的方法来实现这一点(也许使用某种中间件?)。
【问题讨论】:
标签: python django concurrency locking django-signals