Django Rest Framework 的主要部分是视图(ViewSets、ApiViews 等)和序列化程序。这些都不是编写逻辑的理想场所。
正如您所提到的,在任何视图中编写逻辑都不好。为什么?
- 无法从应用的其他部分使用相同的逻辑
- 没办法封装逻辑(需要调用视图为
运行逻辑)
- 无法对逻辑进行单元测试,因为与视图耦合
恕我直言,模型不是编写逻辑的好地方。将模型视为您的数据库定义。我会让它们尽可能简单。您可以覆盖“保存”和其他方法来完成琐碎的任务。任何其他高级功能都应该在它之外。
我可以想到两个更好的地方来满足您的需求:
其中一个是django signal
更好的是自定义类。
在您自己的类中封装/解耦逻辑(您可以使用静态或实例方法,没关系),然后您将能够:
- 对这些方法进行单元测试/模拟该类
- 在其他地方重用这个逻辑
- 根据KISS原则简化你的代码
- 在保持信号代码简单的信号中使用它
- 在 celery 任务中使用它(如果您将来实现它),而无需修改任何一行代码
更新如何组织代码的示例。
从 cmets 可以清楚地看出,信号不起作用,因为分析操作将根据用户请求运行。如果该操作应在保存特定模型时自动运行,则信号将很有用。
我假设您知道如何使用 django-rest-framework api 视图或
视图集,序列化程序等。我不知道,最好问
另一个问题。这将比其他任何东西都更像是一个 python 解释
在您的应用模块中,创建一个文件 app_business_logic.py 或任何您想调用的文件。例如,您可以将其放在 models.py 的同一级别,但这不是强制性的:
class HoldingsAnalyser:
# static method sample. Call it like this: "HoldingsAnalyser.run(..)"
@staticmethod
def run(holding_list):
# do your model generation here or whatever you need
return True # or whatever you need to return
# instance method sample. Create an instance first and then call the method:
# analyser = HoldingsAnalyser()
# analyser.run(...)
def run(self, holding_list):
# do your model generation here or whatever you need
return True # or whatever you need to return
现在,在 django-rest-framework api 视图或视图集中,创建一个 POST 方法,以便在客户端应用用户按下按钮(该按钮生成分析)时调用:
from yourapp.app_business_logic import HoldingsAnalyser
class StockPortfolioViewSet(WhatEverMixingYouNeedToInheritFrom):
serializer_class = whatever # look at the docs
@detail_route(methods=['post'])
def run_analysis(self, request, pk):
stock_portfolio = get the object based on the pk
holdings = make your query to get the holdings
analysis_result = HoldingsAnalyser.run(holdings)
if analysis_result:
# everything ok
return Response(status=status.HTTP_204_NO_CONTENT)
else:
return Response(a useful error for your client)
这个 url 类似于 http://server.com/api_path/stockportfolio/21/run_analysis/,其中 21 是 StockPortfolio 的 id