DRF初探

Web 应用模式

前后端混合开发前后端不分离):返回的是html的内容需要写模板
前后端分离只专注于写后端接口返回jsonxml格式数据

前后端不分离

img

前后端分离

img

API接口

API接口: 规定了前后端信息交互规则的url链接也就是前后台信息交互的媒介
接口文档: 手动编写或者自动生成(coreapiswagger)

RESTful规范

1. 数据的安全保障通常使用https进行传输
2. 域名(api的标识)
   https://api.example.com/      # 尽量部署在API专用域名下
   https://www.example.com/api/
3. 请求地址带版本或者在请求头中
   https://api.example.com/v1/
   https://www.example.com/api/v1
4. 任何东西都是资源均用名词表示(尽量不要用动词)
   https://api.example.com/v1/books/
5. 通过请求方式区分不同操作
   get: 获取数据
   post: 新增数据
   put/patch: put是全部更新patch是局部更新
   delete: 删除
6. 在请求路径中带过滤
   https://api.example.com/v1/?name='三'&order=asc
7. 返回数据中带状态码
   http请求状态码(2xx 3xx 4xx 5xx)
   返回的JSON格式中带状态码(标志当次请求成功或失败)
8. 返回数据中带错误信息
   错误处理应返回错误信息error当做key
9. 对不同的操作返回数据符合如下规范
   GET https://api.example.com/v1/books/       # 返回资源对象的列表(数组) [{},{}]
   GET https://api.example.com/v1/books/1/     # 返回单个资源对象 {}
   POST https://api.example.com/v1/books/      # 返回新生成的资源对象 {新增的数据}
   PUT  https://api.example.com/v1/books/1/    # 返回完整的资源对象  {返回修改后的数据}
   PATCH https://api.example.com/v1/books/1/   # 返回完整的资源对象 {返回修改后的数据}
   DELETE https://api.example.com/v1/books/1/  # 返回一个空文档
   # {status:100,msg:查询成功,data:null}
10 返回结果中带连接

postman的使用

后端写好之后需要测试因此需要一个工具测试接口常用的postman
下载地址: https://www.postman.com/

image-20220314110921244

image-20220314111001390

image-20220314111111514

image-20220314111310044

序列化与反序列化

api接口开发最核心最常见的一个过程就是序列化所谓序列化就是把数据转换格式序列化可以分两个阶段
    1.序列化 把我们语言识别的数据转换成指定的格式提供给别人
              字典列表对象 ---> json/xml/prop,massagepack ---> 提供给别人(前端或其他服务)
    2.反序列化把别人提供的数据转换/还原成我们需要的格式


我们在django中获取到的数据默认是模型对象qs对象),但是模型对象数据无法直接提供给前端或别的平台使用所以我们需要把数据进行序列化变成字符串或者json数据提供给别人 --->序列化过程

前端传入到后台的数据 --->json格式字符串 --->后端存到数据库中需要转成python中的对象 ---> 把json格式字符串转成python对象存到数据库的过程称为反序列化

DRF介绍和安装

介绍和安装

DRF可以更方便的使用django写出符合RESTful规范的接口(不用也可以写出符合规范的接口)
是一个app(需要在settings.py中配置)
安装: pip3 install djangorestframework
官网: https://www.django-rest-framework.org/

简单使用

# csrf已经禁用了
# 路由
path('test/', views.Test.as_view()),

# 视图
from rest_framework.views import APIView
from rest_framework.response import Response
class Test(APIView):
    def get(self, request):
        return Response({'name': 'xxx', 'age': 18})
    def post(self, request):
        return Response({'name': 'yyy', 'age': 20})

# 注册app(settings.py)
  INSTALLED_APPS = [
      ...
      'rest_framework',
      ...
  ]

# 请求地址
  http://127.0.0.1:8000/test/
  # 使用post和浏览器会有不同的结果

DRF的快速使用

models.py

from django.db import models
class Books(models.Model):
    name = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)
    price = models.IntegerField()

app01/serializer.py

from rest_framework.serializers import ModelSerializer
from app01 import models
class BookSerializer(ModelSerializer):
    class Meta:
        model = models.Books
        fields = '__all__'

views.py

from rest_framework.viewsets import ModelViewSet
from app01 import models
from app01.serializer import BookSerializer

class BookView(ModelViewSet):
    serializer_class = BookSerializer
    queryset = models.Books.objects.all()

urls.py

from django.contrib import admin
from django.urls import path
from rest_framework.routers import SimpleRouter
from app01 import views

router = SimpleRouter()
router.register('books', views.BookView)
urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns += router.urls

CBV源码分析

path('test/',views.TestView.as_view()),
    # path('test/',View类的as_view内部有个view闭包函数内存地址)
    '''
    1 path的第二个参数是:View类的as_view内部有个view闭包函数内存地址
    2 一旦有请求来了,匹配test路径成功
    3 执行第二个参数view函数内存地址(requset)
    4 本质执行了self.dispatch(request)
    5 通过反射去获得方法(如果是get请求,就是get方法)
     if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    6 执行get方法,传入参数
    handler(request, *args, **kwargs)
    '''

'''
装饰器函数 csrf_exempt
@csrf_exempt
def test():
    pass

本质就是
test=csrf_exempt(test)
'''

APIview源码分析

    # path('test/',APIView类的as_view内部是用了View的as_view内的view闭包函数),
    '''
    1 path的第二个参数是:APIView类的as_view内部是用了View的as_view内的view闭包函数
    2 一旦有请求来了,匹配test路径成功
    3 执行第二个参数view函数内存地址(requset),还是执行View的as_view内的view闭包函数,但是加了个csrf_exempt装饰器
    4 所以,继承了APIView的所有接口,都没有csrf的校验了 (*****************)
    5 执行self.dispatch(request)----》APIView类的
        def dispatch(self, request, *args, **kwargs):
            # 以后所有的request对象,都是****新的request对象***,它是drf的Request类的对象
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            try:
                #整个drf的执行流程内的权限,频率,认证
                self.initial(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

                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
    '''

## request = self.initialize_request(request, *args, **kwargs)
## 返回的request对象是drf   Request类的request对象
def initialize_request(self, request, *args, **kwargs):
    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )
## ******以后,在视图类中使用的request对象已经不是原来的request对象了,现在都是drf的request对象了

##### 需要记住的
  所有的csrf都不校验了
  request对象变成了新的request对象drf的request对象
  执行了权限频率认证
  捕获了全局异常统一处理异常
  处理了response对象如果浏览器访问是一个样postman访问又一个样
  以后在视图类中使用的request对象已经不是原来的request对象了现在都是drf的request对象了

Request对象分析

1 django 原生的Requestdjango.core.handlers.wsgi.WSGIRequest

2 drf的Requestrest_framework.request.Request

3 drf的request对象内有原生的request
    request._request:原生的Request

4 在视图类中使用
    request.method  拿到的就是请求方式
    正常拿应该request._request.method

5 如何实现这种操作
	-对象.属性会触发 类的__getattr__方法

6 drf的Request类重写了__getattr__
    def __getattr__(self, attr):
        try:
            # 去原生的request反射属性
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)

 7 虽然视图类中request对象变成了drf的request但是用起来跟原来的一样只不过它多了一些属性
   request.data  # post请求提交的数据,不论什么格式,都在它中
   requst.query_params  # get请求提交的数据(查询参数)

8 重点记住
  drf的request对象用起来跟原来一样重写了__getattr__
  request.data  # post请求提交的数据,不论什么格式,都在它中
  requst.query_params  # get请求提交的数据(查询参数)