1

我有一个类似博客的应用程序,其中包含故事和类别:

class Category(models.Model):
    ...
class Story(models.Model):
    categories = models.ManyToManyField(Category)
    ...

现在我知道,当您保存具有多对多字段的模型的新实例时,会出现问题,因为该对象尚未在数据库中。这个问题通常表现在表单提交上,可以巧妙地使用story_form.save(commit=False). 没有形式可言的情况呢?就我而言,我想构建一个 API 来接受远程提交。由于我喜欢 JSON,而且我们公司的许多其他消息都是 JSON 格式(包括来自该服务器的传出消息),我希望能够接收以下内容:

{ "operation": "INSERT",
  "values": [
            { "datatype": "story",
              "categories": [4,6,8],
              "id":50,
              ...
            }
            ]
}

并实现一个将值转换为实例的工厂。但我希望工厂对操作类型尽可能不可知。所以:

{ "operation": "UPDATE",
  "values": [
            { "datatype": "story",
              "categories": [4,6,8],
              "id":50,
              ...
            }
            ]
}

也应该以相同的方式转换,除了 INSERT 忽略 id 并且 UPDATE 获取已经存在的实例并覆盖它。(远程提交者侦听一个提要,除其他外,它还提供要缓存的类别对象,因此它可以而且必须通过 id 引用它们,但它与数据库没有任何直接通信。)

我真正的问题是:对涉及 ManyToManyManager 的 Django 模型对象的实例进行膨胀最简单的方法是什么。据我所知,任何插入具有多对多字段的对象都需要两次数据库命中,因为必须首先获得一个新的 id。但我目前尴尬的解决方案是立即保存对象并将其标记为隐藏,以便后续功能可以使用它并将其保存为更有意义的东西。似乎上一步将被覆盖save,以便没有 id 的对象保存一次,将一些代理字段复制到categories,然后再次保存。最重要的是一些强大的管理器对象可以为我省去麻烦。你有什么建议吗?

4

2 回答 2

3

“据我所知,任何插入具有多对多字段的对象都需要两次数据库命中,......”

所以呢?

微观管理每个单独的数据库访问通常不值得考虑。做最简单、最明显的事情,以便 Django 可以为您优化缓存。

您的应用程序性能——通常——主要由下载到浏览器的速度慢,以及页面中的所有 JPEGS、CSS 和其他静态内容支配。

花在思考如何在不进行两次数据库访问的情况下创建两个主键(对于多对多关系)上的时间不会得到很好的回报。两个 PK 通常是两个数据库访问。


编辑

“......在错误中乱扔数据库......”

Django 有事务。请参阅http://docs.djangoproject.com/en/dev/topics/db/transactions/#managing-database-transactions。使用@transaction.commit_manually装饰器。

“强制验证将在以后发生”

没有意义 - 更新您的问题以解释这一点。

于 2009-04-06T22:34:55.490 回答
2

我评论了 S.Lott 的帖子,我觉得他的回答是最好的。他是对的:如果目标只是避免两次数据库命中,那么您将陷入一个不必要的痛苦世界。

但是,阅读您对 ModelForm 的引用,如果您正在寻找一种解决方案,可以让您以某种方式推迟官方保存,您可能希望查看save_instance(). forms.models内部功能save_m2m是如何为表单完成延迟的多对多保存。为没有表单的模型实现一些东西基本上遵循相同的原则。

话虽如此,回到 S.Lott 的帖子,ModelForm 和实际 Model 的情况有些不同。因为表单只公开了要在浏览器中编辑的“安全”数据集(“安全”是因为它以某种方式被过滤,或者排除了用户不应该编辑的关键字段),所以合理的设计期望是有人可能需要在保存之前向表单派生模型添加重要信息。这就是为什么 django 有commit=False.

对于直接实例化模型的情况,这种期望会下降。在这里,您可以对模型 API 进行编程访问,因此您可能会发现直接使用该 API 比通过通用间接方式更易于维护且不易出错。我可以理解您为什么要描绘工厂概念,但在这种情况下,您可能会发现为各种模型创建防弹泛化的努力是不值得的复杂化。

于 2009-04-06T23:04:11.940 回答