内容概要

  • drf整体知识点

1入门规范

  • web应用模式
  • api接口
  • postman 使用教程
  • restful规范
  • 序列化反序列化
  • 基于django原生框架编写5个接口
  • drf介绍及快速使用
  • cbv源码分析

2序列化组件

  • 基本序列化类
  • 模型类序列化
  • 如何序列化/反序列化
  • 反序列化的数据校验功能

3请求和响应

  • drf的request(不同于django原生request)
  • drf的response(不同于django原生response)
  • 指定接收请求的编码格式
  • 指定发出响应的编码格式

4视图组件

  • 视图组件(2个基类,5个视图拓展类,9个是视图子类,视图集)

5路由

  • 自动生成路由

6认证(登录认证),权限,频率

7过滤,排序,分页

8自动生成接口文档

扩展知识点

9JWT登录认证,区别与cookie和session

10后端管理美化(simpleui二次开发)

11基于角色的访问控制(权限控制)

web应用模式

前后端结合

	# django 是针对web的框架 专门用来编写web项目的

		在此之前我们编写的bbs项目,图书管理系统使用的是 前后端混合开发
		相当于我们既要编写前端页面代码也要编写后端处理数据逻辑代码
		主要是在前端页面编写的时候需要编写python代码(模板语法)
		--> 相当于全栈开发 --> 在前后端混合时代比较多
		

web应用模式/api接口/postman安装(界面简介)/drf安装使用-小白菜博客
前后端分离

		后端人员,不需要接触前端,只需要编写接口即可
		全栈开发>>>>web后端+前端框架(vue,react)

image

API接口

# 为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少双方之间的合作成本【前后端】

# 通过网络,规定了前后台信息交互规则的url链接,也就是前后台信息交互的媒介

# api接口:就是前后端交互的媒介
	-url地址:https://api.map.baidu.com/place/v2/search
    -请求方式:get,post,delete,put。。。。
    -请求参数:json格式的key-value类型数据
    	-早些年 前后端交互使用xml格式----》ajax:异步JavaScript和XML
        -后来,随着json格式的出现,成了主流,直到现在
        -以后:一定会出现,比json更高效的交互格式,更安全
    -响应结果:json格式的数据
# api接口案例
-https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295&region=上海&query=肯德基&output=xml
    
-https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295&region=上海&query=肯德基&output=json
我们分别使用不同的output方式 访问 api接口 返回的不一样类型的数据格式
在图中我们就可以看到区别

image

Postman使用教程

# 作为后端,写好了接口,我们自己需要先测试通过,再给别人用

# 写的接口,需要有个工具测试
	-浏览器只能发送get请求,不能自动发送post,delete请求
	所以需要使用以下工具来辅助解决
    -postman
    -postwoman
    -这个工具只是用来发送http请求!
postman下载安装
https://www.postman.com/downloads/?utm_source=postman-home

image

下载好后直接双击安装即可

image

界面简介

web应用模式/api接口/postman安装(界面简介)/drf安装使用-小白菜博客
web应用模式/api接口/postman安装(界面简介)/drf安装使用-小白菜博客
image

restful规范

# 1.restful概念
	REST全称是Representational State Transfer,中文意思是表述:表征性状态转移,它首次出现在2000年Roy Fielding的博士论文中。
	RESTful是一种定义Web API接口的设计风格,尤其适用于前后端分离的应用模式中
2.10条规范
1.数据的安全保障.我通常都是使用 https(http+ssl/tsl) 协议
	url连接一般都采用Https协议进行传输
	采用https协议传输的好处就是>>> 可以提高数据交互过程中的安全性
2.接口中带api标识
	'地址中带api标识'
	http://api.wunee.cn/
	'路径中带api标识'
	http://wunee.cn/api/book >>> 主要使用这种格式
3.多版本共存>>路径中携带版本信息
	我们在编写项目时可能需要进行更新操作,那么我们之前的项目版本可能还会在进行使用
	且用户不能全部强制更新,这样我们就需要对多版本项目进行共存,以免对用户体验造成影响
		http://api.wunee.cn/version1/login >>>版本1
		
		http://api.wunee.cn/version2/login >>>版本2
4.数据即为资源,均使用名词,尽量不要出现动词(核心)
	接口一般都是完成前端后端数据的交互,交互的数据我们称之为资源
	接口形式:
		http://api.baidu.com/users/ >>> 用户相关接口
		http://api.baidu.com/list/ >>> 订单相关接口
	但是这种接口形式并不能清晰的表明具体作用
	并且存在一些特殊接口,并没有一个明确的资源,比如login
	'特殊的接口可以出现动词'
	http://api/baidu.com/login/
5.资源操作由请求方式决定
		操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查动作
			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  - delete请求:删除主键为1的书
		'主要是运用到以上几种请求方式,也可能是以上几种请求的变种,大体就是这样'
6.请求地址中携带过滤条件
	https://api.baidu.com/books?name=小&price<20
	'相当于我们通过get请求后面的?携带我们需要的过滤条件'
7.响应状态码:两套
	1.http响应状态码:
1xx	响应中--临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它
2xx	成功--重定向到其它地方;它让客户端再发起一个请求以完成整个处理
3xx	重定向--重定向到其它地方;它让客户端发起一个请求以完成整个处理
4xx	客户端错误--处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等
5xx	服务端错误--处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等
	2.公司规定的响应状态码,放在响应体中
		{"code":10000}
8.返回数据中携带错误信息
{"code":10000,"msg":"ok/error"}
9.返回结果应该符合以下规范
GET '获取所有数据':返回资源对象的列表(数组)
相当于[{"name":"xiaoming","age":18},{"name":"dabai","age":12},{"name":"xiaohei","age":38}]
GET '单个对象': 返回单个资源对象 >>> {"name":"dabai","age":12}
POST '新增对象': 返回新生成的资源对象 >>> {"name":"dabai","age":12}
PUT '修改对象': 返回修改后的资源对象 >>> {"name":"dabai","age":13}
DELETE '删除对象' 返回空文档
10.响应数据中带连接
	返回结果中提供链接,连向其他api方法。
 # 示例: 
	{
      "id": 1404376560,
      "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。",
      "url": "http://blog.sina.com.cn/zaku",
      "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1",
      "domain": "zaku",
	}

序列化反序列化

# api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把【数据转换格式】,序列化可以分两个阶段:

# 序列化: 把我们识别的数据转换成指定的格式提供给别人
	-例如:我们在django中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,
	所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人

# 反序列化:把别人提供的数据转换/还原成我们需要的格式。
	-例如:前端js提供过来的json数据,对于python而言就是字符串,
	我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中。

基于django编写5个接口

# 查询全部
	views视图层代码:
class BookView(View):
    def get(self, request):
        book_queryset = models.Book.objects.all()  # 查询出来为queryset对象
        book_list = []
        for book_obj in book_queryset:
            book_list.append({"name": book_obj.name, "price": book_obj.price, "publish": book_obj.publish})
        return JsonResponse(book_list, safe=False)
	urls路由层代码
	from django.contrib import admin
	from django.urls import path
	from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/',views.BookView.as_view()),

image

# 新增一条数据
	views视图层代码:
class BookView(View):
    def get(self, request):
        book_queryset = models.Book.objects.all()  # 查询出来为queryset对象
        book_list = []
        for book_obj in book_queryset:
            book_list.append({"name": book_obj.name, "price": book_obj.price, "publish": book_obj.publish})
        return JsonResponse(book_list, safe=False)

    def post(self, request):
        name = request.POST.get('name')
        price = request.POST.get('price')
        publish = request.POST.get('publish')
        book_obj = models.Book.objects.create(name=name, price=price, publish=publish)
        return JsonResponse({"name": book_obj.name, "price": book_obj.price, "publish": book_obj.publish})

image

# 查询一条数据
因为是查询数据,我们需要新增加一个路由,因为我们需要在路径后面添加过滤条件
views视图层代码
class BookDetailView(View):
    def get(self, request, pk): # 因为使用了转换器所以需要增加一个我们自定义的pk参数
        book_obj = models.Book.objects.filter(pk=pk).first()
        return JsonResponse({"name": book_obj.name, "price": book_obj.price, "publish": book_obj.publish}, safe=False)

urls路由层代码
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/',views.BookView.as_view()),
    path('book/<int:pk>',views.BookDetailView.as_view()) # 使用转换器接收参数
]

image

# 修改一条数据
views视图层代码
class BookDetailView(View):
    def put(self, request, pk):
        # 在put 提交的数据,不能从request.POST中取出
        dic = json.loads(request.body)
        print(dic)
        name = dic.get('name')
        price = dic.get('price')
        publish = dic.get('publish')
        book_obj = models.Book.objects.filter(pk=pk).first()
        book_obj.name = name
        book_obj.price = price
        book_obj.publish = publish
        book_obj.save()
        return JsonResponse({"name": book_obj.name, "price": book_obj.price, "publish": book_obj.publish},safe=False)
urls路由层代码
	path('book/<int:pk>',views.BookDetailView.as_view()) # 使用转换器接收参数

修改数据我们使用PUT请求,但是注意我们在提交修改数据的时候因为put提交数据不能从request.POST中获取,
我们只能在 request.body中取出,我们在携带数据的时候就需要使用原生的raw>>>携带json格式数据到后端进行处理

image

# 删除数据
views视图层代码
    def delete(self,request,pk):
        models.Book.objects.filter(pk=pk).delete()
        return JsonResponse(data={})  # jsonresponse 需要返回一个 空数据 !
urls路由层代码
	path('book/<int:pk>',views.BookDetailView.as_view()) # 使用转换器接收参数

image

drf介绍和快速使用

	djangorestframework: drf可以帮助我们快速的实现符合restful规范的接口
	django 最新到4.x版本 一般我们会使用3.x版本的django
	drf 最新支持到django3.x 但是不支持2.x版本
	我们现在使用的是django的2.2.22版本
	# 安装 drf
	1.我们先安装 djangoframework
		pip3.8 install djangorestframework -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com/simple/
    # 由于你是django2.x 它发现它不支持,它会自动卸载dajgno,安装最新的django 4.x
	# 但是我们在2.2.22版本还有没有编写完的项目,所以我们需要在安装一下2.2.22版本的django即可 
	pip3.8 install django==2.2.22 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com/simple/

快速使用 drf编写接口

我们在django原生项目框架中编写了5个api接口 , 比较繁琐
我们使用drf 即可快速的帮我们实现接口编写!并且符合restful规范
# views中
from .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

# serializer
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
        
# urls中
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', views.BookView, 'books')

urlpatterns = [
    path('admin/', admin.site.urls),
]
# 两个列表相加  [1,2,4] +  [6,7,8]=
urlpatterns += router.urls

CBV 流程推导

在django项目时候已经分析过cbv的流程了
再次分析以下 >>>目的 为什么 cbv 可以 自动触发 不同请求方式的视图函数
首先是 urls 路由层中
path('book/',views.BookView.as_view()),
Bookview.as_view() 执行顺序最高
我们可以看以下 as_view() 源码
@classonlymethod
    def as_view(cls, **initkwargs):
我们可以看到 它是绑定给类的方法
也就是 我们BookView这个类的方法
    @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("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (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)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            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

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
这个函数返回了一个 view ,这个view函数 是在as_view函数内部的!
到这个函数内部它有一行代码
self = cls(**initkwargs)
就相当于是 BookView 生成的 对象,
return self.dispatch(request, *args, **kwargs)
返回了self.dispatch 将 request,和如果携带转换器的参数传入
    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)
handler 通过反射 getattr 拿到 request.method 中的请求方式
并且 return 请求方式(request, *args, **kwargs)
就相当于自动触发了 BookView中的 视图函数