2016-02-19 33 views
5

我有3個模型是相互關聯的,具有一對多的關係。模型方法中的業務邏輯在Django Rest Framework中進行?

  • 模型A可以有許多實例模型B的
  • 模型A可以具有模型C.
  • 模型B的許多情況下可以有模型的許多實例C.

的想法是用戶將創建模型A的實例(如股票投資組合),然後輸入股票持有量(模型C)。模型B適合的地方是我想要基於組合(模型A)中的股票(模型C)運行計算/邏輯並且使用另一個類/模型來跟蹤事情使得生活更容易,因此模型B。

我原本在Django視圖中具有這些計算的邏輯,但是在中讀到了Django的兩個勺子,業務邏輯應該與視圖分開。因此,我將邏輯移至模型A(投資組合)的方法,現在從視圖中調用該方法。這種邏輯循環了股票持有量並創建了模型B的新實例,結果。

我現在有興趣探索Django的其餘框架,以提供一個JavaScript前端(如Angular)的API。我猜測我無法在我的REST界面中進行這種數據操作。但是,此邏輯(模型B中的數據)的結果需要通過REST可見。因此,這種類型的計算/邏輯去哪裏?

回答

11

Django Rest Framework的主要部分是視圖(ViewSets,ApiViews等)和序列化器。這些都不是寫邏輯的理想地方。如你所說,在任何視圖中編寫邏輯都不好。爲什麼?

  1. 沒有辦法用同樣的邏輯從應用
  2. 的另一部分沒有辦法來封裝邏輯(你需要調用視圖的 邏輯運行)
  3. 沒有辦法進行單元測試邏輯,因爲是加上視圖

恕我直言,模型不是一個很好的地方寫邏輯。將模型看作數據庫定義。我會盡可能保持簡單。您可以覆蓋「保存」和其他方法來完成簡單的任務。任何其他高級功能都應該在其外部生存。

我能想到兩個更好的地方適合你需要的東西:

其中之一是django signal

一個更好的是一個自定義類。 包封物/分離的邏輯在自己的類(可以使用靜態或實例方法,它事doesn't),然後你將能夠:

  1. 單元測試這些方法/嘲弄該類
  2. 重用此邏輯別的地方
  3. 簡化根據KISS原則
  4. 從信號用它保持信號代碼簡單
  5. 從芹菜任務使用它(如果你實現這個將來)不修改代碼你的單行代碼

UPDATE一個如何組織代碼的例子。

從評論中可以明顯看出,信號不會工作,因爲分析操作將根據用戶請求運行。如果該操作在保存特定模型時自動運行,則信號將非常有用。

我假設您知道如何使用django-rest-framework api視圖或 視圖集,序列化程序等。我不知道怎麼回事,最好問另一個問題 。這將是比什麼都重要

在您的應用程序模塊的Python解釋,創建一個文件app_business_logic.py或任何你想將它命名。您可以在models.py例如同一級別的地方,但it's不是強制性的:現在

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的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

+0

感謝@xleon爲的id響應。我仍然不確定所有這些(信號或自定義類)適合於哪個項目。 我在設想一個用戶將在他們的投資組合(模型A)中查看他們的持股(模型C)。然後,他們可以通過單擊「分析」按鈕來運行分析(循環遍歷每個持有和創建模型B實例)。最終,所有3個模型都將通過REST API提供。如果用戶沒有運行分析,那麼模型B的API將是空的。如果分析邏輯在被調用來填充模型B API時處於信號或自定義類中? – shudoh

+0

如果通過用戶操作運行分析,django信號不是一個選項(只有當保存其他模型時自動運行分析時才推薦)。我會用你的工作流程 – xleon

+0

哇的一些僞碼更新答案。很好的例子。我一直想知道如何在models.py中放置業務邏輯。一些流行的出版物表明這是放置它的地方,但我一直有我的懷疑。 –