I have 3 models that are related to each other with one-to-many relationships.
The idea is that a user would create an instance of Model A (like a stock portfolio) and then enter stock holdings (Model C). Where Model B fits in is that I want to run calculations/logic based on the stocks (Model C) in the portfolio (Model A) and using another class/model to keep track of things makes life easier, hence Model B.
I originally had the logic for these calculations in a Django view but read in Two Scoops of Django that business logic should be separated from views. As a result I moved the logic to a method of Model A (the portfolio) and now call that method from a view. This logic loops through the stock holdings and creates new instances of Model B, the results.
I am now interested in exploring django-rest-framework to provide an API to a javascript frontend (like Angular). I am guessing that I will not be able to have this kind of data manipulation within my REST interfaces. However, the result of this logic (data in Model B) needs to be visible via REST. Therefore, where does this type of calculation/logic go?
Django Rest Framework main pieces are views (ViewSets, ApiViews, etc) and serializers. Neither of those are ideal places to write logic. As you mentioned, writing logic in any view is not good. Why?
IMHO, models are not a good place to write logic. Think of a model as your database definition. I would keep them as simple as possible. You can override "save" and other methods to do trivial tasks. Any other advanced functionality should live outside of it.
I can think of two better places for what you need:
One of them is a django signal
A better one is a custom class. Encapsulate/decouple the logic in your own class (you can use static or instance methods, it doesn´t matter), and then you will be able to:
UPDATE An example of how to organize the code.
From the comments it´s clear that a signal wouldn´t work because the analysis operation will run on user request. A signal would be useful if that operation should run automatically when saving an specific model.
I´m assuming you know how to use django-rest-framework api views or viewsets, serializers, etc. I you don´t how about that, better ask another question. This is going to be more a python explanation than anything else
In your app module, create a file app_business_logic.py
or whatever you want to call it. You can place it at the same level of the models.py for instance, but it´s not mandatory:
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
Now, in a django-rest-framework api view or viewset, create a POST method to be called when the client app user press the button (that button to generate analysis):
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)
The url for this would be something like http://server.com/api_path/stockportfolio/21/run_analysis/
, where 21 would be the id of the StockPortfolio
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With