Django从模型或视图调用REST API?
我需要在Django中调用外部的REST API。这些外部数据源的结构和我的Django模型很相似。我需要保持远程数据和本地数据的同步(这可能和问题无关)
问题:
- 从哪个地方调用外部网络服务最合适:是从模型的方法里,还是从视图里?
- 我应该把调用远程API的代码放在外部模块里,然后在视图中调用这些模块吗?
- 有没有可能根据条件选择数据源?也就是说,能根据数据的新鲜程度来决定是展示REST API的数据还是本地模型的数据?
谢谢
编辑:对于那些想要关闭这个问题的人:我一开始就把问题分成了三个简单的问题,到目前为止我得到了很好的回答,谢谢。
2 个回答
从哪里调用外部网络服务最合理:从模型方法还是从视图?
理想情况下,你的模型应该只和数据库打交道,不应该知道你的业务逻辑在干什么。
我应该把调用远程API的代码放在外部模块里,然后再由视图调用吗?
如果你需要在多个模块中访问这些代码,那就应该放在一个模块里。这样可以高效地重复使用这些代码。
是否可以根据条件选择数据源?也就是说,根据数据的“新鲜度”来决定是从REST API获取数据还是从本地模型获取数据?
当然可以。你只需要实现如何根据请求来获取数据。不过,更有效的方法可能是避免这种复杂的逻辑,直接将本地数据和远程数据同步,然后在视图中显示本地数据。
我觉得在哪里调用网络服务是个见仁见智的问题。我认为不要把你的模型搞得太复杂,因为这意味着你可能需要这些模型的实例来调用这些网络服务,这样做可能没有意义。另一种选择是把这些功能做成模型的
@classmethod
,但我觉得这样设计不太干净。如果是通过视图来触发网络服务的调用,那从视图中调用可能更自然。你提到需要保持同步,这可能意味着需要一些后台处理。在这种情况下,如果你的后台处理发出http请求,还是可以使用视图,但这通常不是最好的设计。如果可以的话,你可能更希望有自己的REST API,这样就需要把代码和普通网站的视图分开。
我认为这些调用应该放在专门处理远程调用和处理的模块和类中。这样做让事情更灵活(比如后台任务、信号等),而且也更容易进行单元测试。你可以在视图或其他地方触发调用这些代码,但逻辑本身应该和视图、模型分开,这样可以更好地解耦。
你可以想象,如果没有Django,这些逻辑应该独立存在,然后再构建其他部分把这些逻辑连接到Django(例如:同步模型)。换句话说,保持事情的原子性。
是的,原因和上面的一样,特别是灵活性。有什么理由不这样做吗?
是的,简单地创建一个接口的等价物。让每个类映射到这个接口。如果字段相同而你又懒得处理,在Python中你可以直接把需要的字段作为字典传给构造函数(使用
*kwargs
),这样就可以了,或者使用某种约定重命名键。我通常会为此构建一个简单的数据映射类,并在列表推导中处理Django或REST模型,但如果字段匹配的话就没必要了。另一个相关的选择是,你可以把数据放入像Redis或Memcache这样的缓存中。 如果你担心“新鲜度”,可能需要原子性地更新这些信息。但一般来说,你应该有一个单一的权威来源来告诉你什么是最新的。在同步的情况下,我认为最好选择一个来保持事情的可预测性和清晰性。
最后一点可能会影响你的设计,那就是保持同步本身就是个困难的过程。同步往往容易失败,所以你应该有某种持久的机制,比如任务队列或作业系统来进行重试。调用远程REST API时,永远要假设调用可能因为各种原因失败,比如网络问题。同时在同步时也要考虑事务和事务行为。因为这些都很重要,这再次说明如果你把所有逻辑直接放在视图中,可能会在后台重用时遇到麻烦,所以最好还是稍微抽象一下。