为什么Django ORM的`save`方法不返回已保存的对象?

50

有没有关于这个设计决策背后的原因的见解?在我看来,让obj.save()返回一些东西,只有好处(比如方法链接),没有坏处。

3个回答

74
通常在Python中,具有主要影响现有对象而不是返回对象本身的函数被认为是良好的实践。例如,sorted(yourlist)返回一个已排序的列表,但yourlist.sort()原地对列表进行排序且不会返回任何内容。
在单行上执行具有副作用的多个操作(与无副作用函数相反,其中重点是返回值)并不是一个很好的实践。代码在行数方面更紧凑,但阅读起来会更加困难,因为重要的副作用可能被深埋在链的中间。如果想要使用方法链,请使用没有副作用的函数作为链的开头,然后在结尾使用带有单个副作用函数(例如.save())。
换句话说,在方法链中,链的开头是输入,链的中间转换输入(遍历树,排序输入,更改字符串大小写等),链的末尾是具有副作用的功能部分。如果将具有副作用的方法深埋在链的中间,则将不清楚您的方法链实际上执行了什么操作。

实际上,save() 返回已保存的对象,也许在 Django 1.5 中是新的功能? - maazza
3
我尝试在Django 1.5.1上运行了一下,发现save()仍然返回None。最新开发版本的源代码也似乎没有返回任何内容。 - Andrew Gorcester
true,我使用了一个 ModelForm。https://dev59.com/hWs05IYBdhLWcg3wIOfS - maazza
1
@maazza 哦,我明白了。我觉得这是一个不同的情况,因为你在表单上调用.save(),它返回的是一个不同的对象,而不是它本身。顺便说一句,我认为如果ModelForm没有.save(),而是有一个方法来在内存中实例化一个对象而没有副作用,就像User()实例化一个User对象一样,会更清晰。然后你可以在那个对象上调用.save()。但这只是我的个人意见,可能还有其他问题我没有考虑到,阻止这样做。 - Andrew Gorcester
这个答案可能是最好的,但如果你想要返回一个对象,只需使用.save(commit=False)。 https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method - trpt4him

8
这让我想起了Greg Ward在Pycon2015上提出的一个通用原则,不要混淆函数和过程。每个函数应该返回一个值或者具有副作用,但不能同时存在两者。
基本上相同的问题也被问到了dict.update()。

5

作为搜索“django return saved object”时得到的第一个结果,为了补充Andrew的答案,如果你仍然想要返回已保存的对象,而不是使用:

ExampleModel(title=title).save()

如果一个函数返回None,则可以使用:

saved_instance = ExampleModel.objects.create(title=title)

这很有效,因为ExampleModel.objects是一个模型管理器而不是类的实例,所以它不会返回自身。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接