【问题标题】:Archiving Django models归档 Django 模型
【发布时间】:2014-02-27 22:36:58
【问题描述】:

我正在创建一个在线订购系统,用于定期销售商品(蔬菜盒送货上门)。我有一个“订单”模型(简化)如下:

class BoxOrder(models.Model):
    customer = models.ForeignKey(Customer)
    frequency = models.IntegerField(choices=((1, "Weekly"), (2, "Fortnightly)))
    item = models.ForeignKey(Item)
    payment_method = models.IntegerField(choices=((1, "Online"), (2, "Free)))

现在我的“客户”可以更改订单的频率,或更改出售的“商品”(比如“胡萝卜”),甚至可以一起删除订单。

我想做的是为该周处理的所有订单创建每周“备份”,这样我就可以看到每周售出的所有订单的历史图表。仅将订单归档到另一个表/数据库的问题是,如果某个项目(比如我不再出售胡萝卜)由于某种原因被删除,那么归档的 BoxOrder 将因为 ForeignKeys

而变得无效

使用 Django 创建归档系统的最佳解决方案是什么 - 以便在 Django 管理员中查看历史上每周的订单,并且它们是“静态的”(即与是否删除任何其他对象无关)? 我考虑过创建一个新的“平面”BoxOrderArchive 模型,然后使用 cron 作业来移动给定一周的订单,例如:

class BoxOrderArchive(models.Model):
    customer_name = models.CharField(max_length=20)
    frequency = models.IntegerField()
    item_name = models.CharField() # refers to BoxOrder.item.name
    item_price = models.DecimalField(max_digits=10, decimal_places=2) # refers to BoxOrder.item.price
    payment_method = models.IntegerField()

但我觉得这可能是很多额外的工作。在我走这条路之前,很高兴知道是否有人有其他解决方案?

谢谢

【问题讨论】:

    标签: python django cron foreign-keys


    【解决方案1】:

    这是一个相当广泛的话题,我不会专门回答你的问题,但是我给你的建议是不要删除或移动任何东西。您可以在 Item 中添加一个名为 is_deletedis_active 或类似名称的布尔字段,并在删除项目时使用该标志。这样你就可以

    • 保留您的ForeignKeys,
    • 对非活动项目有不同的表示
    • 恢复之前删除的Item(例如,您可能想在几个月后再次出售胡萝卜 - 这样您的统计数据将在全年保持一致)

    BoxOrder 模型也有同样的建议。不要将行删除到不同的表中,只需添加一个is_archived 字段并将其设置为True

    【讨论】:

    • 我应该提到我已经考虑过这个想法,但问题要复杂得多。实际上不删除BoxOrder 项目不会存储它的历史。问题是,BoxOrder 项目会随着时间的推移而变化,所以我真正需要的是每周的快照——当然,理想情况下外键仍然存在。
    • 我仍然不明白为什么您需要从数据库中实际删除行。对于对象的历史,我建议使用github.com/treyhunner/django-simple-history(如果您还想实际查询快照-因为字段按原样复制)或github.com/etianen/django-reversion(如果您只想能够查看或恢复)之类的解决方案对象的旧版本)
    • 是的,我刚刚找到了 django-simple-history,我在想;使用 that+is_deleted 就可以了。 django-reversion 似乎是另一种选择。更好的文档,但看起来只有在通过管理界面编辑时才会保存修订。使用 is_deleted 的唯一缺点是我不能使用 Django 的 DeleteView,这是一个(非常小的)缺点
    • 你当然可以实现自己的DeleteView。此外,django reversion works 在管理员之外 - 您只需将 reversion.middleware.RevisionMiddleware 添加到您的 MIDDLEWARE_CLASSES (当然从 reversion.VersionAdmin 继承您的 Admin 类)
    • 还想指出,虽然使用布尔字段的解决方案有效,但它对表格来说有点乱,并且不一定是规范化的。但是,应用程序确实有优先级,所以我想如果你想保持这些数据非规范化,这是个人喜好。
    【解决方案2】:

    因此,经过漫长而艰苦的研究,我认为对我来说最好的解决方案是创建对象的“平面”版本,取消引用任何现有对象,并将其保存在数据库中。

    原因是我的“BoxOrder”对象每周都会发生变化(因为客户会编辑他们的地址、商品、成本等。跟踪所有这些变化非常困难。 另外,除了显示给网站用户之外,我不需要对数据做任何事情。

    基本上我想做的是创建一个快照,而现有的工具都不是我想要的。话虽如此,其他人可能有不同的优先级,所以这里有一个有用的链接列表:

    [1]SO question regarding storing a snapshot/pickling model instances

    [2] Django Simple History Docs - 在每次创建/更新/删除时存储模型状态

    [3] Django Reversion Docs - 允许恢复模型实例

    有关 [2] 和 [3] 的讨论,请参阅 Serafim 回答中的 cmets

    【讨论】:

      猜你喜欢
      • 2015-02-27
      • 1970-01-01
      • 1970-01-01
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 2018-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多