我正在使用 django 框架编写一个应用程序,并正在考虑编写类似休息控制器的东西,因为将异常处理逻辑保留在一个地方似乎是一个好主意。我不知道执行此操作的正确方法是什么,但我想出了一个装饰器,其中包含一堆可能由各种方法引发的异常,因此,每个方法都使用该装饰器。
def exception_handler(function):
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except Error1 as error:
return Response(
{"Error": str(error)},
status=status.HTTP_400_BAD_REQUEST
)
except Error2 as error:
return Response(
{"Error": str(error)},
status=status.HTTP_404_NOT_FOUND
)
except Error3 as error:
return Response(
{"Error": str(error)},
status=status.HTTP_503_SERVICE_UNAVAILABLE
)
return wrapper
Run Code Online (Sandbox Code Playgroud)
其中Error1、Error2和Error3只是一些抽象错误。在我的应用程序中确实有更多这样的情况。
简单的控制器(又名 django 视图)可能看起来像这样:
class DeviceView(viewsets.ModelViewSet):
lookup_field = 'id'
serializer_class = DeviceSerializer
@exception_handler
def create(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(data=request.data)
return Response(status=status.HTTP_200_OK)
Run Code Online (Sandbox Code Playgroud)
因此,基本上,如果抛出任何异常,都会以适当的方式进行处理。我在这里看到的问题之一是,如果不是我提出带有所需消息的异常:
if some_condition:
raise SomeException("Something happened")
Run Code Online (Sandbox Code Playgroud)
这将是默认的,我通常更愿意更改它。因此,我开始对控制向客户显示哪些消息感到有些不舒服。我现在能想到的最好的办法是:
try:
this_function_throws_someexception(args)
except SomeException:
raise SomeException("Here is the message I want to show to the client")
Run Code Online (Sandbox Code Playgroud)
这意味着我必须重新引发抛出的异常以及我希望引发的消息。我的第一个问题是“这是处理这个问题的最佳方法吗?”。第二个问题是:“整个异常处理方法好吗?”
书籍和专业人士推荐使用的方法是进行mixin和双重继承。
当使用DOUBLE INHERITANCE时,Mixin 上写入的所有内容都将重叠/覆盖并与第一个导入合并。
class A:
function gives a
no var defined
exception 1
class Bmixin:
function gives b
var is b
class X(A, Bmixin):
function gives b
exception 1
var is b (first was a but then was overriden by the Mixin because the
function is named equally)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,X 类拥有两个类中的所有内容,并且覆盖了两个类中类似定义的内容。
通常,您定义一个基本的 ErrorHandling Mixin 和一些更具体的 Mixin,然后根据最终视图的需要堆叠尽可能多的 Mixin。
A 类(ViewStuff、ErrorBasicMixin、ErrorMoreSpecificMixin):
首先,你将所有的东西放在一个类上,最后以 Mixin 的名称命名(只是一个约定,但非常有用),其中包括你想要添加到类中的额外内容,在本例中是所有异常。
例如
class ErrorHandlingMixing(): #No need of inheritance inside brackets "()"
#code
Run Code Online (Sandbox Code Playgroud)
大多数人为 mixins 制作不同的 .py 文件,例如 mixins.py
然后将其导入到您的视图中:
from .mixins import ErrorHandlingMixing
Run Code Online (Sandbox Code Playgroud)
并在创建视图类时进行双重继承
class User (AmbstractBaseUser, PermissionsMixin):
#code
Run Code Online (Sandbox Code Playgroud)
还有很多已经为此创建的 mixin,例如 PermissionsMixin
from django.contrib.auth.models import PermissionsMixin
Run Code Online (Sandbox Code Playgroud)
我会给你一个来自 github 的 mixins.py 的例子
我想说装饰器方法更倾向于决定是否应该处理视图,例如使用权限。我认为你可以尝试使用装饰器来做到这一点,但 Mixins 看起来更干净,重复性更少,并且是专业人士的默认方法。
亲切的问候