加载中...

djangorestframework基础使用


前言

djangorestframework 也叫 drf,在使用 drf 之前我们需要先知道什么 REST

REST(Representational State Transfer,表现层状态转移)是一种软件架构风格,它不是一种标准,也不是一种技术,而是一种设计Web服务的方法。

RESTful是一种定义Web API接口的设计风格,尤其适用于前后端分离的应用模式中。

了解RESTful

RESTful架构的优点

  • 前后端分离:前端负责展示和渲染,后端负责处理数据并以JSON格式传输出去。这样的统一接口在Web、iOS、Android三端都可以使用,减少了重复代码的编写。
  • 无状态:每次请求都包含了所有必要的信息,这使得每个请求都是独立的,服务器不需要保存任何客户端的状态,从而更容易实现服务的扩展。

RESTful架构的缺点

  • 无状态约束:虽然无状态增加了可扩展性,但对于需要保存用户状态的应用来说,每次请求都需要包含所有信息,可能会导致请求变得复杂。

RESTful架构的约束条件

  • 客户端-服务器结构:客户端和服务器之间通过统一的接口进行通信。
  • 无状态:服务器不保存任何客户端的状态。
  • 可缓存:响应需要被标记为可缓存或不可缓存,以减少客户端和服务器之间的交互。
  • 统一接口:系统中的所有交互都是通过统一的接口进行的,这使得系统中的各个部分可以独立地进行演化2

RESTful架构的实现

在实现RESTful架构时,需要注意以下几点:

  • 使用HTTP方法:GET用于获取资源,POST用于创建资源,PUT用于更新资源,DELETE用于删除资源。
  • 资源的表述:资源可以有多种表述形式,客户端和服务器通过内容协商来确定资源的表述方式。
  • 资源的链接:资源的表述应该包含链接,这些链接指向了资源的操作或相关资源,使得客户端可以通过这些链接进行状态转移。

RESTful规范

十条规范如下:

  1. 数据的安全保障

    url链接一般都采用https协议进行传输 注:采用https协议,可以提高数据交互过程中的安全性。

  2. 接口特征表现,一看就知道是个api接口

    - 用api关键字标识接口url:
        - [https://api.baidu.com](https://api.baidu.com/)
        - https://www.baidu.com/api
        注:看到api字眼,就代表该请求url链接是完成前后台数据交互的
  3. 多数据版本共存

    - 在url链接中标识数据版本, 场景:比如移动端接口升级,但是不能影响老接口
    - https://api.baidu.com/v1
    - https://api.baidu.com/v2
  4. 数据即是资源,均使用名词(可复数)

    - 接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
    	- https://api.baidu.com/users
        - https://api.baidu.com/books
    	- https://api.baidu.com/book
    
    注:一般提倡用资源的复数形式,在url链接中奖励不要出现操作资源的动词,错误示范:https://api.baidu.com/delete-user
    - 特殊的接口可以出现动词,因为这些接口一般没有一个明确的资源,或是动词就是接口的核心含义
    	- https://api.baidu.com/place/search
        - https://api.baidu.com/login
  5. 资源操作由请求方式决定(method)

    - 操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查动作
    	- https://api.baidu.com/books - get请求:获取所有书
        - https://api.baidu.com/books/1 - get请求:获取主键为1的书
        - https://api.baidu.com/books - post请求:新增一本书书
       	- https://api.baidu.com/books/1 - put请求:整体修改主键为1的书
    	- https://api.baidu.com/books/1 - patch请求:局部修改主键为1的书
    	- https://api.baidu.com/books/1 - delete请求:删除主键为1的书
  6. 过滤,通过在url上传参的形式传递搜索条件

    - https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
    - https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
    - https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
    - https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
    - https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
  7. 响应状态码

    7.1 正常响应
        - 响应状态码2xx
            - 200:常规请求
            - 201:创建成功
    7.2 重定向响应
        - 响应状态码3xx
            - 301:永久重定向
            - 302:暂时重定向
    7.3 客户端异常
        - 响应状态码4xx
            - 403:请求无权限
            - 404:请求路径不存在
            - 405:请求方法不存在
    7.4 服务器异常
        - 响应状态码5xx
            - 500:服务器异常
  8. 错误处理,应返回错误信息,error当做key

    {
        error: "无权限操作"
    }
  9. 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范

    GET /collection:返回资源对象的列表(数组)
    GET /collection/resource:返回单个资源对象
    POST /collection:返回新生成的资源对象
    PUT /collection/resource:返回完整的资源对象
    PATCH /collection/resource:返回完整的资源对象
    DELETE /collection/resource:返回一个空文档
  10. 需要url请求的资源需要访问资源的请求链接

    # Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么
    {
        "status": 0,
        "msg": "ok",
        "results":[
            {
                "name":"肯德基(罗餐厅)",
                "img": "https://image.baidu.com/kfc/001.png"
            }
            ...
        ]
    }

DjangoRESTframework简单使用

drf官方文档:https://www.django-rest-framework.org/

安装

在安装之前,请确认自己django版本是否支持。我这里使用 djangorestframework==3.15.2 版本,要求如下:

  • Django(4.2、5.0)
  • Python(3.8、3.9、3.10、3.11、3.12)

使用pip安装:

pip install djangorestframework==3.15.2

简单使用

对于普通写法,使用 drf 时和之前区别不大。只不过 drf 提供了很多便利性的功能。比如认证、权限、频率三大组件。高级用法请看后面的文章。

setting.py配置

# 在setting.py的app中注册
INSTALLED_APPS = [
    '......',
    'rest_framework',
    'django_filters',  # 可选,只有使用到filter时才需要配置
]

# 可选配置:根据实际使用情况来使用
REST_FRAMEWORK = {
    # 设置全局默认渲染器
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',               # json格式展示响应
        'rest_framework.renderers.BrowsableAPIRenderer',       # 网页渲染格式展示响应(rest默认渲染)
    ]
    # 配置全局认证
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',   # rest默认验证
        'rest_framework.authentication.SessionAuthentication', # rest默认验证
        'app01.app_auth.MyAuthentication',                     # 自定义认证类
    ],
	# 配置全局权限
    'DEFAULT_PERMISSION_CLASSES': [       
        'rest_framework.permissions.IsAuthenticated',          # rest默认权限
        'app01.app_auth.UserPermission',                       # 自定义权限
    ],
	# 配置全局访问频率
    'DEFAULT_THROTTLE_CLASSES': [   # 访问频率策略
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {     # 访问频率速率:值包括second、minute、hour或day作为节流周期。
        'anon': '100/day',
        'user': '1000/day'
    },
	# 配置全局过滤器,需要安装`pip3 install django-filter`,且在app中注册
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend'
    ]
}

视图使用

from rest_framework.views import APIView
from rest_framework.response import Response

class BookView(APIView):
    def get(self, request):
        ret = {
            "data": [{
                "name": "djangorestframework基础使用",
                "author": "wuye",
                "price": "66.66"
            },{
                "name": "djangorestframework基础使用(二)",
                "author": "wuye",
                "price": "66.66"
            }]
        }
        return Response(ret)

这就是最简单的使用了。

djangorestframework源码分析

cbv源码

# 先读View的源码:  Django==4.2.16
from django.views import View

# urls.py
path('books1/', views.Books.as_view()),  #在这个地方应该写个函数内存地址,views.Books.as_view()执行完,是个函数内存地址,as_view是一个类方法,类直接来调用,会把类自动传入
# 放了一个view的内存地址(View--》as_view--》内层函数)

# 请求来了,如果路径匹配,会执行:函数内存地址(request), 返回结果又调用了self.dispatch()
class View:
    def as_view(cls, **initkwargs)
    	pass
        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)
        pass
        return view

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        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)

APIView源码分析

#from rest_framework.views import APIView
# urls.py
path('booksapiview/', views.BooksAPIView.as_view()),  #在这个地方应该写个函数内存地址


class APIView(View):
    #APIView的as_view方法(类的绑定方法)
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs)  # 调用父类(View)的as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        # 以后所有的请求,都没有csrf认证了,只要继承了APIView,就没有csrf的认证
        return csrf_exempt(view)

#请求来了---》路由匹配上---》view(request)---》调用了self.dispatch(),会执行apiview的dispatch
    
    # APIView的dispatch方法
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # 重新包装成一个request对象,以后再用的request对象,就是新的request对象了
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 三大认证模块
            self.initial(request, *args, **kwargs)
            # Get the appropriate handler method
            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
            # 响应模块
            response = handler(request, *args, **kwargs)
        except Exception as exc:
            # 异常模块
            response = self.handle_exception(exc)
        # 渲染模块
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
   
    # APIView的initial方法
 	def initial(self, request, *args, **kwargs):
        # 认证组件:校验用户 - 游客、合法用户、非法用户
        # 游客:代表校验通过,直接进入下一步校验(权限校验)
        # 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
        # 非法用户:代表校验失败,抛出异常,返回403权限异常结果
        self.perform_authentication(request)
        # 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
        # 认证通过:可以进入下一步校验(频率认证)
        # 认证失败:抛出异常,返回403权限异常结果
        self.check_permissions(request)
        # 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
        # 没有达到限次:正常访问接口
        # 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
        self.check_throttles(request)

文章作者: 无夜
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 无夜 !
评论
  目录