Django Rest Framework业务逻辑

39

我正在尝试使用Django Rest Framework创建后端,并试图确定业务逻辑应放在哪里。它会放在views.py中吗?我想创建比仅获取对象列表或抓取一个特定对象更复杂的服务。任何指导将不胜感激,谢谢。我知道有关通用Django项目中业务逻辑的讨论,但我特别询问django rest框架。


1
已经有一个关于这个问题的大讨论了:https://dev59.com/ymcs5IYBdhLWcg3wym4h - Spencer
2
是的,我看过那个,但希望能够具体询问一下在Django Rest Framework中的位置。 - perp
你找到一个好的设计模式了吗?谢谢。 - jhagege
3个回答

33

这更多是关于设计模式而不是Django Rest Framework。

以下是一些提示:

  • 使用REST提供接口不应涉及任何与数据操作或业务逻辑相关的特定代码。
  • 使用MVC方法并不意味着您不应分层应用程序。
  • 您应该能够在完全不触摸UI的情况下测试您的业务逻辑。
  • 有些人可能会建议将业务逻辑放入模型中。但我不同意,因为Django模型与领域模型和业务相关任务(如税收计算)不同。
  • 在陷入MVC之前,您可以阅读有关在MVC三层架构中实现的MVC
  • 我建议设置业务层和相关应用程序来放置您的业务逻辑。

MVC + three-tier diagram

假设您有一个在线咖啡店,您想为订购咖啡提供REST API。

以下是我建议的代码示例:

myapp/views.py:

    def order(request, quantity=1):
        # Process the order by calling the mapped method
        order_id = CoffeeShopService.place_order(quantity)
        return HttpResponse({'order_id': order_id, mimetype='application/json')

我的应用程序/services.py:

    class CoffeeShopService(object):
        @staticmethod
        def place_order(quantity):
           # do the business logic here
           return order_id

谢谢您的见解。但是我在实施您的想法时遇到了另一个问题。我很难标准化我的异常处理。正如您所知,在DRF中我们有“ValidationError”。在视图集中还有另一个异常,例如在模型中也有许多异常类。问题在于这些错误处理在API响应中具有不同的格式。 - Adiyat Mubarak
2
DRF(Django Rest Framework)中的异常处理是一个不同的问题,可以通过自定义异常处理来实现。如果你搜索一下,你可以找到如何处理异常,或者你可以提出一个单独的问题。 - Saeed
我最近开始使用Python和Django进行编码,在此之前,我一直在使用Java/Spring Boot进行编码。我非常同意您的观点,不应该把逻辑放在models.py中,使其变得更加笨重。在我看来,services模块是执行某些业务流程的最佳位置。这个想法源自于我对Spring Boot的经验。 - catscoolzhyk

2
这是一个关于Rest框架中设计模式探究的内容,我猜测。下面是我在Rest框架上使用分层方法构建API的详细概述!
为了方便维护,它采用了更多的分层,并且最重要的是利用了设计模式和GRASP原则!
分层方法的包级视图。

enter image description here

进一步分类:

enter image description here enter image description here

现在举个例子,展示我如何穿过各个层级:
一个请求被发到了example.com/Customer/profile 在@project/urls.py中 enter image description here 请求被转发到了相应的URL层(@app/urls/Customer_Url) The Request is forwarded to the Respective URL's Layer URL将其传递给相应的Viewset (@app/Viewsets/Customer_Viewsets/Customer_Signup.py) enter image description here 由于这是一个Post请求(对于此示例),因此它被转发到了业务逻辑层 (@app/BusinessLogicLayer/BLL.py) enter image description here 业务逻辑层具有抽象实现(充当IBLL接口),它将请求转发到相应的方法以检查所有我的业务规则! (@app/BusinessLogicLayer/SUB_BLL/Customer/*) enter image description here 然后请求被转发到数据访问层,该层将用户数据存储在数据库中。等等!(@app/DataAccessLayer/DAL.py)

2
Customer_Name is "" 这是明显的错误,通常代码存在问题。你应该使用验证框架(例如Marshmallow)。 - warvariuc
1
我基本上是为了处理一些自定义的事情而设置一个空字符串,这个API被数十个设备所交互!此外,这段代码是我的团队成员编写的,所以他最好能够解释清楚。我的主要目标是概述分层架构。如果不是客户名称,我会使用其他东西 :) - Syed Faizan
1
@warvariuc,如果您能在架构方面指出错误,我将不胜感激,因为我自己更注重长期使用,所以我真的很想修复我的架构错误。最重要的是,非常感谢 :) - Syed Faizan
1
当使用驼峰命名法、重复的代码和错误的低级语言习惯时,很难判断架构。此外,过多的信息和截图而非文本也会造成困扰。在我看来,我只看到了代码和解释,但没有描述代码中使用的设计原则。 - warvariuc
1
@warvariuc 目前,我正在攻读软件工程专业的学生,已经完成了1年的学习,还有3年的时间要度过 :)。在这个阶段,我自己支持自己 :),如果我们可以通过电子邮件或Skype进行交流,我希望能够从您的知识中学到更多并不断成长。 - Syed Faizan
显示剩余2条评论

-4
也许这是一种略微偏离常规的方式,但我认为将逻辑封装到序列化器中并在其中添加方法非常有帮助。
例如:
序列化器:
class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = (
            'id',
            'total',
            'discount',
        )

    def calculate_discount(self, whatever_params):
        # calculate discount if you need... and return it

    def calculate_tax(self, whatever_params):
        # calculate tax amount if you need...and return it

    def calculate_grand_total(self, whatever_params):
        # calculate grand total if you need and return it

    def create(self, validated_data):
        # You can make an order by applying 
        # some logic in the calculation method.
        # Maybe by adding a bit of the context 
        # you sent as parameters from view.

2
即使可以这样做,我认为将逻辑放入序列化程序并不明显也是错误的。因为序列化程序的主要思想只是对数据进行序列化和反序列化,并进行一些验证工作。从django项目架构的角度来看,这是不正确的。 - catscoolzhyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接