Где бизнес-логика в модельном методе идет в Django Rest Framework?

У меня есть 3 модели, которые связаны друг с другом отношениями один ко многим.

  • модель A может иметь много экземпляров модели B.
  • модель A может иметь много экземпляров модели C.
  • модель B может иметь много экземпляров модели С.

идея заключается в том, что пользователь создаст экземпляр модели A (например, портфель акций), а затем введите stock holdings (модель C). Где модель B вписывается в то, что я хочу запустить вычисления / логику основываясь на акциях (модель C) в портфеле (модель A) и используя другой класс/модель, чтобы отслеживать вещи, облегчает жизнь, следовательно, модель B.

У меня изначально была логика для этих вычислений в представлении Django, но читайте в две ложки Джанго бизнес-логика должна быть отделена от представления. В результате я переместил логику в метод модели A (портфолио) и теперь вызываю этот метод из представления. Эта логика петляет по фондовым запасам и создает новые экземпляры модели B, результаты.

теперь мне интересно исследовать django-rest-framework, чтобы предоставить API для интерфейса javascript (например, Angular). Я предполагаю, что я не смогу иметь такого рода манипуляцию данными в моих интерфейсах REST. Однако результат этой логики (данные в модели B) должен быть виден через REST. Таким образом, куда идет этот тип вычисления/логики?

1 ответов


основные части Django Rest Framework-это представления (ViewSets, ApiViews и т. д.) и сериализаторы. Ни то, ни другое не является идеальным местом для написания логики. Как вы упомянули, писать логику в любом виде нехорошо. Почему?

  1. нет способа использовать ту же логику из другой части приложения
  2. нет способа инкапсулировать логику (вам нужно вызвать представление для логика для запуска)
  3. нет способа модульного тестирования логики, потому что в сочетании с вид

IMHO, модели не являются хорошим местом для написания логики. Подумайте о модели как об определении базы данных. Я постараюсь сделать все как можно проще. Вы можете переопределить "сохранить" и другие методы для выполнения тривиальных задач. Любая другая расширенная функциональность должна жить за ее пределами.

Я могу придумать два лучших места для того, что вам нужно:

один из них -сигнал Джанго

лучшим является пользовательский класс. Инкапсулировать / разъединить логика в вашем собственном классе (вы можете использовать статические методы или методы экземпляра, это не имеет значения), и тогда вы сможете:

  1. модульный тест этих методов / макет этого класса
  2. повторно использовать эту логику где-то еще
  3. упростите свой код в соответствии с поцелуй принцип
  4. используйте его из сигнала, сохраняя код сигнала простым
  5. используйте его из задачи сельдерея (если вы реализуете это в будущем) без изменения одной строки ваш код

обновление пример того, как организовать код.

из комментариев ясно, что сигнал не будет работать, потому что операция анализа будет выполняться по запросу пользователя. Сигнал будет полезен, если эта операция должна выполняться автоматически при сохранении определенной модели.

Im предполагая, что вы знаете, как использовать представления api django-rest-framework или viewsets, сериализаторы, etc. Я тебе не как насчет этого, лучше просить другой вопрос. Это будет больше объяснение 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

теперь в представлении api django-rest-framework или наборе представлений создайте метод 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