Django ORM:缓存和操作 ForeignKey 对象
Posted
技术标签:
【中文标题】Django ORM:缓存和操作 ForeignKey 对象【英文标题】:Django ORM: caching and manipulating ForeignKey objects 【发布时间】:2010-10-15 09:14:00 【问题描述】:考虑以下用于太空征服游戏的 models.py 框架:
class Fleet(models.Model):
game = models.ForeignKey(Game, related_name='planet_set')
owner = models.ForeignKey(User, related_name='planet_set', null=True, blank=True)
home = models.ForeignKey(Planet, related_name='departing_fleet_set')
dest = models.ForeignKey(Planet, related_name='arriving_fleet_set')
ships = models.IntegerField()
class Planet(models.Model):
game = models.ForeignKey(Game, related_name='planet_set')
owner = models.ForeignKey(User, related_name='planet_set', null=True, blank=True)
name = models.CharField(max_length=250)
ships = models.IntegerField()
我正在处理的一个项目中有许多这样的数据模型,并且我根据各种数据对象之间有些复杂的交互来更改游戏的状态。我想避免对数据库进行大量不必要的调用,所以每回合一次,我会做类似的事情
-
从数据库中查询所有舰队、行星和其他对象,并将它们缓存为 python 对象
处理游戏对象,解析游戏状态
将它们保存回数据库中
这个模型在使用 ForeignKey 对象时似乎完全崩溃了。例如,当一个新舰队离开一个星球时,我有一条看起来像这样的线:
fleet.home.ships -= fleet.ships
在这行代码运行之后,我还有其他代码可以改变每个行星上的船只数量,包括行星fleet.home。不幸的是,上一行所做的更改并没有反映在我之前获得的行星查询集中,因此当我在回合结束时保存所有行星时,对舰队.home 的船只的更改会被覆盖。
有没有更好的方法来处理这种情况?或者这就是所有 ORM 的样子?
【问题讨论】:
【参考方案1】:这也许就是你要找的:
https://web.archive.org/web/20121126091406/http://simonwillison.net/2009/May/7/mmalones/
【讨论】:
【参考方案2】:Django 的 ORM 没有实现 identity map(它在 ticket tracker 中,但不清楚是否或何时实现;至少一个核心 Django 提交者有 expressed opposition to it)。这意味着如果您通过两个不同的查询路径到达同一个数据库对象,那么您正在使用内存中的不同 Python 对象。
这意味着您的设计(一次将所有内容加载到内存中,修改很多内容,然后在最后全部保存)使用 Django ORM 是不可行的。首先是因为它通常会在同一对象的重复副本中浪费大量内存加载,其次是因为“覆盖”问题,例如您遇到的问题。
您要么需要重新设计以避免这些问题(要么小心一次只使用一个 QuerySet,在进行另一个查询之前保存任何修改过的内容;或者如果您加载多个查询,请手动查找所有关系,永远不要使用方便的属性遍历 ForeignKeys),或者使用实现标识映射的替代 Python ORM。 SQLAlchemy 是一种选择。
请注意,这并不意味着 Django 的 ORM 是“糟糕的”。它针对 Web 应用程序的情况进行了优化,这类问题很少见(我已经使用 Django 进行了多年的 Web 开发,并且从未在实际项目中遇到过这个问题)。如果您的用例不同,您可能需要选择不同的 ORM。
【讨论】:
是的,非常感谢您提供的信息丰富的回复。我知道这并不意味着 Django 的 ORM 不好;其实我用django开发了一个完整的项目,不需要这种复杂的数据处理,从来没有出现过这个问题,所以我很茫然。以上是关于Django ORM:缓存和操作 ForeignKey 对象的主要内容,如果未能解决你的问题,请参考以下文章
Django基础---web框架 和 django 介绍3 --model --form---跨站请求---cookie--session--分页--缓存--信号