Django Rest Framework中模型方法中的业务逻辑在哪里?

时间:2016-02-19 14:49:13

标签: python django django-rest-framework

我有3个模型,彼此之间有一对多的关系。

  • 模型A可以有许多模型B的实例。
  • 模型A可以有许多模型C的实例。
  • 模型B可以有许多模型C的实例。

想法是用户将创建模型A的实例(如股票投资组合),然后输入股票持有(模型C)。模型B适合的地方是我想根据投资组合(模型A)中的股票(模型C)运行计算/逻辑,并使用另一个类/模型来跟踪事物,使生活更轻松,因此模型B。

我最初在Django视图中有这些计算的逻辑,但在 Django的两个Scoops 中读取业务逻辑应该与视图分开。结果,我将逻辑移动到模型A(投资组合)的方法,现在从视图中调用该方法。这个逻辑循环通过股票持有并创建模型B的新实例,即结果。

我现在有兴趣探索django-rest-framework来为javascript前端提供API(比如Angular)。我猜我在REST接口中无法进行这种数据操作。但是,此逻辑(模型B中的数据)的结果需要通过REST显示。因此,这种类型的计算/逻辑在哪里?

1 个答案:

答案 0 :(得分:16)

Django Rest Framework的主要部分是视图(ViewSets,ApiViews等)和序列化器。这些都不是编写逻辑的理想场所。 正如您所提到的,在任何视图中编写逻辑都不是很好。为什么?

  1. 无法使用应用程序其他部分的相同逻辑
  2. 无法封装逻辑(您需要调用视图 要运行的逻辑)
  3. 无法对逻辑进行单元测试,因为它与视图相结合
  4. 恕我直言,模型不是写逻辑的好地方。将模型视为数据库定义。我会让它们尽可能简单。您可以覆盖“保存”和其他方法来执行琐碎的任务。任何其他高级功能都应该在它之外生效。

    我能想到两个更适合你需要的地方:

    其中一个是django signal

    更好的是自定义类。 封装/解耦您自己的类中的逻辑(您可以使用静态或实例方法,这无关紧要),然后您将能够:

    1. 单元测试那些方法/模拟该类
    2. 在其他地方重复使用此逻辑
    3. 根据KISS原则
    4. 简化您的代码
    5. 从保持信号代码简单的信号中使用它
    6. 从celery任务中使用它(如果您将来实现它),而无需修改代码的任何一行
    7. 更新如何整理代码的示例。

        

      从评论中很清楚,信号不起作用,因为分析操作将根据用户请求运行。如果在保存特定模型时该操作应自动运行,则信号将非常有用。

           

      我假设您知道如何使用django-rest-framework api视图或   viewsets,serializers等。我不是那个怎么样,更好问   另一个问题。这将是一个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)
      

      这个网址就像http://server.com/api_path/stockportfolio/21/run_analysis/,其中21将是StockPortfolio的ID