当前位置:  开发笔记 > 编程语言 > 正文

Django ORM:缓存和操作ForeignKey对象

如何解决《DjangoORM:缓存和操作ForeignKey对象》经验,为你挑选了1个好方法。

考虑以下用于空间征服游戏的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

在这条线路运行之后,我还有其他代码可以改变每个行星上的船只数量,包括行星舰队.遗憾的是,上述行中所做的更改并未反映在我之前获得的行星的QuerySet中,因此当我在转弯结束时保存所有行星时,对fleet.home船只的更改将被覆盖.

有没有更好的方法来处理这种情况?或者这就是所有ORM的方式?



1> Carl Meyer..:

Django的ORM没有实现身份映射(它在故障单跟踪器中,但不清楚它是否或何时实现;至少有一个核心Django提交者表示反对它).这意味着如果通过两个不同的查询路径到达同一个数据库对象,则表示您正在使用内存中的不同Python对象.

这意味着您的设计(一次将所有内容加载到内存中,修改很多内容,然后将其全部保存到最后)使用Django ORM是行不通的.首先是因为它通常会浪费大量内存加载到同一对象的重复副本中,其次是因为"覆盖"问题,例如您正在遇到的问题.

您需要重新设计您的设计以避免这些问题(要么小心一次只使用一个QuerySet,在进行另一个查询之前保存修改的内容;或者如果您加载多个查询,请手动查找所有关系,不要永远遍历ForeignKeys使用方​​便的属性),或使用实现身份映射的替代Python ORM. SQLAlchemy是一个选项.

请注意,这并不意味着Django的ORM"糟糕".它针对Web应用程序进行了优化,这些问题很少见(我已经用Django进行了多年的Web开发,而且从未在真正的项目中遇到过这个问题).如果您的用例不同,您可能想要选择不同的ORM.

推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有