zoukankan      html  css  js  c++  java
  • DRF(一)

    一.HTTP协议与wsgi协议

    http协议
        应用层协议
        请求与响应规范:首行 - 头 - 体
        特点:无状态、无连接、请求永远是客户端到服务器端、ssl
        
    wsgi协议
        原生django启动项目 - 启动了server socket - wsgiref - uWSGI(项目上线)
        规定数据的解析方式:
            get数据、post数据(数据数据) => request => 回调的视图函数
            返回响应对象 - HTTPResponse类对象 - 数据、响应状态码

    二.接口

    url链接:http://api.oldboy.com/login/
    请求方式:get | post | put ...
    请求参数:username | password
    响应结果:result | data

    利用Postman连接百度接口:

    method: GET
    url: https://api.map.baidu.com/place/v2/search
    params:
        ak: 6E823f587c95f0148c19993539b99295
        region: 上海
        query: 肯德基
        output: json

    原生Djiango实现接口:

    models.py

      from django.db import models
      class Book(models.Model):
         name = models.CharField(max_length=64)
         price = models.DecimalField(max_digits=5, decimal_places=2)
         class Meta:
            db_table = 'old_boy_book'
            verbose_name = '书籍'
            verbose_name_plural = verbose_name
         def __str__(self):
            return self.name

    class User(models.Model):
        SEX_CHOICES = [
            (0, ''),
            (1, ''),
            (2, '哇塞')
        ]
        username = models.CharField(max_length=64)
        password = models.CharField(max_length=64)
        sex = models.IntegerField(choices=SEX_CHOICES, default=0)
        # 需要配置media工作目录与路由
        icon = models.ImageField(upload_to='icon', default='/icon/default.png')
        class Meta:
            db_table = 'old_boy_user'
            verbose_name = '用户'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.username
    创建Django项目并设置默认app名为api,完成路由分发:
    
    
    # 主路由
    from django.conf.urls import url, include
    from django.contrib import admin
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api/', include('api.urls')),
    ]
    
    # api应用下的子路由
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        # as_view() 本质拿到 view函数地址,
        # view内部通过dispatch分发请求给具体的(get|post|delete)方法处理请求
        # 处理完后的响应结果会一层层返回
        url(r'^books/$', views.BookView.as_view()),
        url(r'^books/(?P<pk>.*)/$', views.BookView.as_view()),
    ]

    数据库迁移:
    
    >: python manage.py makemigrations
    >: python manage.py migrate
    后台管理:
    
    from django.contrib import admin
    from . import models
    admin.site.register(models.Book)
    admin.site.register(models.User)
    
    # 创建超级用户
    # >: python manage.py createsuperuser
    views.py
    
    from django.views import View
    from django.http import JsonResponse
    from . import models
    class BookView(View):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:  # 通过是否有主键决定获取单个或是全部资源
                book_dic_list = models.Book.objects.filter(pk=pk).values('name', 'price')
                if not book_dic_list:
                    return JsonResponse({
                        'status': 2,
                        'msg': 'pk值有误',
                        'results': {}
                    })
                return JsonResponse({
                    'status': 0,
                    'msg': 'ok',
                    'results': book_dic_list[0]
                })
    
            book_dic_list = models.Book.objects.all().values('name', 'price')
            if not book_dic_list:
                return JsonResponse({
                    'status': 2,
                    'msg': '无数据',
                    'results': {}
                })
            return JsonResponse({
                'status': 0,
                'msg': 'ok',
                'results': list(book_dic_list)
            })

    开一个media窗口:

    ##### media工作目录:settings.py
    
    ```python
    # MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    ```
    
    ##### 路由:主urls.py
    
    ```python
    from django.conf.urls import url, include
    from django.contrib import admin
    
    from django.views.static import serve
    from django.conf import settings
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api/', include('api.urls')),
        url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
    ]
    ```

    三.restful接口十条规范

    1)一般都采用安全协议(接口都是操作数据的):https
    
    2)体现接口的关键字:api
        https://api.oldboy.com
        https://www.oldboy.com/api
    
    3)接口操作的数据称之为资源:采用资源名称的复数
        https://api.oldboy.com/books/
        https://api.oldboy.com/users/
    
    4)接口链接中不出现操作资源的动词,通过请求方式来决定操作资源的动作
        https://api.oldboy.com/books/
        get:获取所有 | post:增加一个 
        https://api.oldboy.com/books/(?P<pk>)/
        get:获取一个 | put:整体修改一个(patch:局部修改一个) | delet:删除一个
    
    5)资源数据有多版本时,接口可以做版本控制
        https://api.oldboy.com/books/v1/
        https://api.oldboy.com/v2/books/
        
    6)资源响应的限制条件:筛选、排序、限制...
        https://api.oldboy.com/books/?publish=1&ordering=-price&limit=3
        
    7)响应状态码
        网络状态码:2xx | 3xx | 4xx | 5xx
        数据状态码(约定的):0 | 1 | 2
        {
            'status': 1,
        }
        -- SUCCESS(0, "查询成功")
        -- NODATA(1, "非正确,无数据,显示基本信息")
        -- FEAILED(2, "查询失败")
    
    8)响应结果的信息描述:
        {
            'status': 1,
            'msg': 'login failed'
        }
    
    9)响应的结果:get所有:所有资源 | get一个:一个资源 | post、put、patch:新增、修改的资源 | delete:不做任何返回
        {
            'status': 0,
            'msg': 'ok',
            'results': [登录的用户对象序列化结果]
        }
        
    10)响应结果中有二次资源(用户头像:图片链接,用户详情:详情接口)
        要表明请求二次资源的接口
    
    注:通过 接口文档 告诉前台传递的必要和选填参数

    四.drf框架

    安装:

    pip3 install djangorestframework
    配置:settings.py
    # 注册drf app
    NSTALLED_APPS = [
        # ...
        'rest_framework',
    ]

    特点:

    # 具体功能在具体模块下
    from rest_framework.request import Request
    from rest_framework.response import Response
    from rest_framework.exceptions import APIException
    from rest_framework.filters import OrderingFilter
    from rest_framework.views import APIView
    from rest_framework.pagination import PageNumberPagination
    from rest_framework.settings import APISettings
    
    # 自定义drf配置 - 在自己的settings.py
    REST_FRAMEWORK = {
        # 自定义修改drf的配置们
    }

    五.源码分析APIView

            1.django中的CBV:

     url(r'^books/', views.Books.as_view()),

               发现Books类调用as_view方法,自身类没有则找父类View, 进入源码发现它返回的是view的函数地址,

    请求来了,则根据路由匹配去找视图函数,依然会找到父类View中的view函数,返回的是self.dispatch方法,self指的是Book

    对象,自身没有,还是找父类中的dispatch方法;

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

             首先判断方法名小写在不在django支持的这八种方法里面,如果在,并且Book类中有此方法,以反射获取方法值赋予句柄

    handle,否则赋予 http_method_not_allowed方法的返回值给handle,状态码是405, 最后将handle返回;获取正确方法则进入视图

    函数,并将响应结果逐层返回.

              2.rest_framework中的CBV:

              Book类继承的是APIView, 而APIView继承的是View, APIView是从rest_framework框架中导进来的,as_view方法返回的

    是 csrf_exempt(view),也就是不会经过csrf中间件认证;

              请求来了调用view函数,内部调用(APIView类的)dispatch函数完成请求分发;

           request = self.initialize_request(request, *args, **kwargs)

             dispatch中对request进行了一次封装,在initialize_request函数中返回的的是Request类的一个实例化,看它的__init__方法就

    发现把原生django的request对象当做Request类对象的_request属性,所以封装后的request._request仍然是wsgi的request对象,

    而request变成了rest_framework的request对象

            dispatch还在self.initial中完成了三大认证: 认证/权限/频率

            再将请求方式映射到视图函数的同名的方法中,得到响应后渲染,并将响应结果逐层返回

    六.响应渲染模块:json和浏览器接口页面

    # 入口:APIView类的dispatch函数
    self.response = self.finalize_response(request, response, *args, **kwargs)
    ->
    neg = self.perform_content_negotiation(request, force=True)
    ->
    renderers = self.get_renderers()
    ->
    self.renderer_classes
    ->
    APISetting:DEFAULT_RENDERER_CLASSES
       局部配置(在视图函数中):
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    from rest_framework.renderers import JSONRenderer
    from rest_framework.renderers import BrowsableAPIRenderer
    class UserAPIView(APIView):
        # 局部配置:只有该视图类起作用
        renderer_classes = [JSONRenderer]  # 只提供JSON数据渲染
        pass

      

    全局配置(在django的settings.py文件中):
    # drf配置
    REST_FRAMEWORK = {
        # 响应的渲染模块
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        ],
    }

    七.请求数据解析模块:json、form-data、urlencoding

     

    # 入口:APIView类的dispatch函数
    request = self.initialize_request(request, *args, **kwargs)
    ->
    parsers=self.get_parsers()
    ->
    self.parser_classes
    ->
    APISetting:DEFAULT_PARSER_CLASSES

    局部配置:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    from rest_framework.parsers import JSONParser
    from rest_framework.parsers import FormParser
    from rest_framework.parsers import MultiPartParser
    class UserAPIView(APIView):
        # 局部配置:只有该视图类起作用
        parser_classes = [JSONParser]  # 只提供JSON解析
        pass

    全局配置:

    # drf配置
    REST_FRAMEWORK = {
        # 响应的渲染模块
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        ],
        # 请求数据解析模块
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',  # 'application/json'
            'rest_framework.parsers.FormParser',  # 'application/x-www-form-urlencoded'
            'rest_framework.parsers.MultiPartParser'  # multipart/form-data
        ],
    }

    请求数据解析位置:

     请求的数据包:均解析到 request.data 中
     请求的?文件参数(get请求url拼接参数):均解析到 request.query_params 中

    八.响应模块

    # 响应可以设置响应数据、响应网络状态码、响应头、响应数据类型等
    data = {
        'status': 0,
        'msg': 'get ok',
        'results': [],
        'token': '123.12321.231'
    }
    return Response(
        data=data,
        status=status.HTTP_200_OK,
        headers={'Token': '123as.masd21.asd213sd'},
        content_type='application/json'  # 默认就是application/json
    )
  • 相关阅读:
    是否是轮回(续)
    夜雨做成秋
    53分
    浮生六记 一成长星和月
    企业信息化常见缩略语汇总
    是否是轮回
    对信号集操作函数的使用方法和顺序
    fcntl.h
    关于linux信号量的基本使用
    linux 共享内存
  • 原文地址:https://www.cnblogs.com/sima-3/p/11448976.html
Copyright © 2011-2022 走看看