drf框架的源码解读之接口设计

86 阅读2分钟

关于drf框架的一些知识点

为什么我在设计接口的时候,一般都定义get,post,put等方法函数,能不能换成其他名字呢,关于这个问题,我们需要看apiview的相关代码,这里需要要求对面向对象的基础有一定的理解。

首先,我们在urls.py中会在类名后面加上.as_view()方法,如下图所示

image.png 来看他的源码

@classmethod
def as_view(cls, **initkwargs):
    if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
        def force_evaluation():
            raise RuntimeError(
                'Do not evaluate the `.queryset` attribute directly, '
                'as the result will be cached and reused between requests. '
                'Use `.all()` or call `.get_queryset()` instead.'
            )
        cls.queryset._fetch_all = force_evaluation
    view = super().as_view(**initkwargs)
    view.cls = cls
    view.initkwargs = initkwargs
    return csrf_exempt(view)

这里调用后返回的这个csrf_exempt(view),表示返回一个无需csrf验证的view,接着我们看view函数返回的值是什么

我们看这下面的代码

@classonlymethod
def as_view(cls, **initkwargs):
    """Main entry point for a request-response process."""
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError(
                "The method name %s is not accepted as a keyword argument "
                "to %s()." % (key, cls.__name__)
            )
        if not hasattr(cls, key):
            raise TypeError(
                "%s() received an invalid keyword %r. as_view "
                "only accepts arguments that are already "
                "attributes of the class." % (cls.__name__, key)
            )

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        self.setup(request, *args, **kwargs)
        if not hasattr(self, "request"):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        return self.dispatch(request, *args, **kwargs)

    view.view_class = cls
    view.view_initkwargs = initkwargs

    view.__doc__ = cls.__doc__
    view.__module__ = cls.__module__
    view.__annotations__ = cls.dispatch.__annotations__
    # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
    # the dispatch method.
    view.__dict__.update(cls.dispatch.__dict__)

    # Mark the callback if the view class is async.
    if cls.view_is_async:
        markcoroutinefunction(view)

    return view

最后的返回值是这个view函数,所以我们来看view函数的返回值 第25行我们可以看到返回的是dispatch这个函数,接下来我们去这个函数看看

def dispatch(self, request, *args, **kwargs):
    if request.method.lower() in self.http_method_names:
        handler = getattr(
            self, request.method.lower(), self.http_method_not_allowed
        )
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

我们看代码的意思,如果请求方式小写后在self.http_method_names里面,那么我们会调用这个方法我们进去查看这里面是什么发现如下:

http_method_names = [
    "get",
    "post",
    "put",
    "patch",
    "delete",
    "head",
    "options",
    "trace",
]

所以,当我们的请求方式在这个列表里面的任意一个时,我们即可通过getattr方法找到我们设计的接口函数并且调用它,所以这也就是我们设计接口时为什么不能够随意更改函数的名称的原因了。