DRF~ day02 之Restful规范、序列化和反序列化、drf介绍和快速使用、drf之APIView源码分析

DRF之Restful规范、序列化和反序列化、drf介绍和快速使用、drf之APIView源码分析


文章目录


一、Restful规范

RESTful是一种定义API接口的设计风格,API接口的编写规范,尤其适用于前后端分离的应用模式中
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源
我们可以使用任何一个框架都可以实现符合restful规范的API接口
10条Restful API接口规范

1、 数据的安全保障,通常使用https协议进行传输

https://www.baidu.com/
# 注:采用https协议,可以提高数据交互过程中的安全性

2、 url地址中带接口标识:一般这样

 用api关键字标识接口url:
   	-https://api.baidu.com
    -https://www.baidu.com/api

3、 多版本共存,url地址中带版本信息

在url链接中标识数据版本
	https://api.baidu.com/v1/login/
	https://api.baidu.com/v2/login/
	注:url链接中的v1、v2就是不同数据版本的体现(只有在一种数据资源有多版本情况下)

4、 数据即是资源,均使用名词:

     url地址尽量使用名词
     # 接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
     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、资源操作由请求方式决定

	#操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查动作
    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、url地址中带过滤条件 ?后带过滤条件

	https://api.baidu.com/books -get请求表示查询所有图书,要查名字中有红的图书
   	https://api.baidu.com/books?name_contains=红
   	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、响应状态码(http响应中带状态码)

	-http的响应状态码:https://blog.csdn.net/meng2lin/article/details/128955775
    	-1xx:请求正在处理
        -2xx:请求成功 200:常规请求  201:创建成功
        -3xx:重定向  301:永久重定向   302:暂时重定向
        -4xx:客户端错误  403:请求无权限   404:请求路径不存在  405:请求方法不存在
        -5xx:服务的错误  500:服务器异常
    -http的响应的数据中带状态码(公司自己规定的)
    	-{code:100}

8、返回的数据中带错误信息

	{code:101,msg:用户名或密码错误}
   	{code:100,msg:成功}

9、返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范

     GET  /books:返回资源对象的列表(数组)
 		-[{name:金瓶梅,price:88},{name:西游记,price:88}]
     	-{code:100,msg:成功,data:[{name:金瓶梅,price:88},{name:西游记,price:88}]}
     GET /books/1:返回单个资源对象
     	-{name:金瓶梅,price:88}    ---{code:100,msg:成功,data:{name:金瓶梅,price:88}}
     POST /books:返回新生成的资源对象
     	-{id:4,name:金瓶梅,price:88}  ---{code:100,msg:成功}
     PUT /books/4:返回完整的资源对象
     	-{id:4,name:金瓶梅,price:188}  ---{code:100,msg:修改成功}
     DELETE /books/4: 返回一个空文档      ---{code:100,msg:删除成功}

10、 返回的结果中带url链接


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

二、序列化和反序列化

# api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段:
	# 序列化: 把我们识别的数据转换成指定的格式提供给别人。
	例如:我们在django中获取到的数据默认是模型对象(queryset),但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。

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

三、基于序列化和反序列化实现book表的增删查改5个接口

-查询所有图书
-新增一本图书
-修改一本图书
-查询一本图书
-删除一本图书

3.1、models.py (模型层)

from django.db import models


# 创建表
class Book(models.Model):
    name = models.CharField(max_length=64)
    peice = models.IntegerField()


# 创建好了之后进行数据迁移
# 终端下,执行数据迁移。
python39 manage.py makemigrations
python39 manage.py migrate

3.2、urls,py(路由层)

    # 开设接口
    # 查询所有图书接口
    path('books/', views.books.as_view()),
    # # 查询一本图书接口
    path('booksfirst/<int:pk>/', views.Booksfirst.as_view()),
    # # 新增一本图书接口
    path('Bookcreate/', views.Bookcreate.as_view()),
    # # 修改一本图书接口
    path("Bookupdata/<int:pk>/", views.Bookupdata.as_view()),
    # # 删除一本图书接口
    path('Bookdelete/<int:pk>/', views.Bookdelete.as_view()),

3.3、view.py(视图层)

# 导入对应模块
from django.http import JsonResponse
from app01 import models
from django.views import View

# 查看所有书籍用get请求
class books(View):
    def get(self, request):
    	# orm语法查询所有的书籍数据
        user_obj = models.Book.objects.all()
        print(user_obj)  # 查询出来的是个对象,字典类型
        books = []
        for book in user_obj:
            books.append({'name': book.name, 'price': book.peice})
        print(books)
        return JsonResponse({'code': 100, 'msg': '成功', 'result': books})  # 序列化数据给到前端

# 查看一本书籍
class Booksfirst(View):
    def get(self, request, pk):
        print(request.method)
        book = models.Book.objects.filter(pk=pk).first()
        books_dict = {'name': book.name, 'price': book.peice}
        return JsonResponse({'code': 200, 'msg': '成功', 'data': books_dict})   # 序列化数据给到前端


# 修改书籍 用put请求
class Bookupdata(View):
    def put(self, request, pk):
        print(request.method)  # put
        # book_data = models.Book.objects.filter(pk=pk).first()
        # print(book_data)  # Book object (3)
        # print(request.body)  # b'{"name": "kevin", "age":18}'
        # print(json.loads(request.body))   # {'name': 'kevin', 'age': 18}  接收前端数据用request.body
        res = json.loads(request.body)  # 接收前端的数据进行反序列化
        print(res)
        print(res['name'])
        print(res['price'])
        user_obj = models.Book.objects.filter(pk=pk)
        if not user_obj:
            models.Book.objects.filter(pk=pk).delete()
        data = '参数id错误,书籍库没有这个id'
        models.Book.objects.filter(pk=pk).update(name=res['name'], peice=res['price'])
        book_data = models.Book.objects.filter(pk=pk).first()
        return JsonResponse({'code': 200, 'msg': data, 'data': book_data})  # 序列化数据给到前端


# 新增书籍
class Bookcreate(View):
    def post(self, request):
        print(request.method)
        # print(request.POST)
        print(request.body)
        print(json.loads(request.body))  # 接收前端的数据进行反序列化
        res = json.loads(request.body)
        models.Book.objects.create(name=res['name'], peice=res['price'])
        return JsonResponse({'code': 200, 'msg': '成功', 'data': 1232})  # 序列化数据给到前端

# 删除书籍
class Bookdelete(View):
    def delete(self, request, pk):
        print(request.method)
        print(json.loads(request.body))
        res = json.loads(request.body)
        print(res)
        user_obj = models.Book.objects.filter(pk=pk)
        if not user_obj:
            models.Book.objects.filter(pk=pk).delete()
        data = '参数id错误,书籍库没有这个id'
        # models.Book.objects.filter(pk=pk).delete()
        return JsonResponse({'code': 200, 'msg': data, 'data': data }) 

四、drf介绍和快速使用

3.1、drf介绍(Django Rest_Framework)

django 中有个app,djangorestframework:简称 drf,它能帮助我们,快速实现符合resful规范的接口

核心思想: 缩减编写api接口的代码

Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。

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

drf的特点:

1、提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
2、提供了丰富的类视图、Mixin扩展类,简化视图的编写;
3、丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
4、多种身份认证和权限认证方式的支持;[jwt]
5、内置了限流系统;
6、直观的 API web 界面;
7、可扩展性,插件丰富

3.2、 环境安装与配置

3.2.1、DRF需要以下依赖:

  • Python解释权的版本 (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
  • Django框架的版本 (1.10, 1.11, 2.0)
  • DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)

3.2.2、下载:(有个坑)

  1. pip下载:pip3.8 install djangorestframework==版本号
  2. 注意事项:如果你是django2, 直接这样装,装最新drf,他们不匹配—》pip会自动把django卸载,安装最新django,安装最新drf。解决方法:把drf版本下降几个版本进行安装就可以了
  3. django3 ,这样没有任何问题,直接安装即可
  4. 安装命令:pip3.8 install djangorestframework --upgrade 这个命令是如果drf版本太低了强制更新到最新的版本

补充一点:
如果写了一个包,或app,想给别人用—》把你写的包,放到pypi上别人pip install 安装—》使用
官网:https://pypi.org/

3.3、drf的快速使用

3.3.1、urls.py(路由层)

from app01.views import BookView
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', BookView, 'books')
urlpatterns = [
]
urlpatterns += router.urls

3.3.2、view.py(视图层)

from .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

3.3.3、models.py(模型层)

from django.db import models

# Create your models here.


class Book(models.Model):
    name = models.CharField(max_length=64)
    peice = models.IntegerField()

3.3.4、创建文件serializer.py(序列化类)

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

3.3.5、这样postman就可以实现前面的根据不同的请求方式实现(基于序列化和反序列化实现book表的增删查改5个接口)了。

在这里插入图片描述

五、使用APIView + 序列化类 + Response 写Book表的5个接口

5.1、模型层建表数据

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=64)
    peice = models.IntegerField()

5.2、创建序列化类(即serializer.py文件)

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'


5.3、开设路由

    # 基于APIView的5个接口
    path('book/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),

5.4、视图层代码

from rest_framework.response import Response  # 导入序列化模块
from rest_framework.views import APIView  # 导入apiview模块  APIView继承了django原来的View


class BookView(APIView):
    # 查所有的书籍
    def get(self, request):
        res = models.Book.objects.all()
        # drf 提供了序列化类
        ser = BookSerializer(instance=res, many=True)   # 序列化
        return Response({'code': 100, 'msg': '成功', 'result': ser.data})

    # 新增一条数据
    def post(self, request):
        ser = BookSerializer(data=request.data)  # 反序列化
        if ser.is_valid():  # 数据校验---》有些不合法的禁止
            ser.save()  # 保存到数据库中
        return Response({'code': 100, 'msg': '成功'})


class BookDetailView(APIView):
    # 查询单条数据
    def get(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, many=False)  # 序列化  查询单条用false,多条用True
        return Response({'code': 100, 'msg': '成功', 'result': ser.data})

    # 修改一条数据
    def put(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)  # 反序列化
        if ser.is_valid():  # 数据校验---》有些不合法的禁止
            ser.save()  # 保存到数据库中
        return Response({'code': 100, 'msg': '成功'})

    # 删除一条数据
    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

5.5、postman展示

BookView类的get方法查询所有数据
在这里插入图片描述
在这里插入图片描述

BookView类的post方法x新增一条数据数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

BookDetailView 查询一条数据在这里插入图片描述
修改一条数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
删除一条数据
在这里插入图片描述
在这里插入图片描述

六、CBV源码分析

# cbv写法:
# cbv写法:
	1 视图中写视图类,继承View,写跟请求方式同名的方法
    	class BookView(View):
            def get(self,request):
                return 四件套
     2 在路径用写
    	path('books/', BookView.as_view())
        
        
        
# 如上写法,为什么能够执行

# 前置条件:前端请求,一旦路径匹配成功,就会执行  BookView.as_view()(request传入,)
# 入口在  BookView.as_view()--->执行结果---》View中有个as_view类的绑定方法
    @classmethod
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            res=self.dispatch(request, *args, **kwargs)
            return res
        return view
    
# 执行结果是view 的内存地址: 请求来了,执行view(request)
	path('books/', view)
    
# 执行 View类中的as_view方法中的内层的view函数,路由匹配成功,本质是在执行
	self.dispatch(request, *args, **kwargs)
    # self是谁的对象?BookView的对象
    # 去BookView中dispatch,找不到,去父类,View中找到了
    
    
# View这个类的dispatch
    def dispatch(self, request, *args, **kwargs):
        # request.method.lower() 如果是get请求,  ‘get’ 在这个列表里面
        if request.method.lower() in self.http_method_names:
            # handler=getattr(BookView的对象,'get')   
            # handler就是BookView类中的get方法
            handler = getattr(self, request.method.lower())
        else:
            handler = self.http_method_not_allowed
        # 执行 BookView类中的get方法 (request)
        return handler(request, *args, **kwargs)
    
# 最终本质跟写fbv的执行流程一样
# 最终结论:什么请求方式,就会执行视图类中的什么方法


七、APIView的执行流程

# 有了drf,后期都写CBV,都是继承APIView及其子类
# 执行流程:
	-入口:path('books/', BookView.as_view())---》请求来了,执行BookView.as_view()(request)
    -as_view 是谁的? APIView的as_view
        @classmethod
        def as_view(cls, **initkwargs):
            # super()代指的是:父类对象  View类的对象
            # View的as_view(**initkwargs)----》执行结果是view,是View类的as_view方法中的view
            view = super().as_view(**initkwargs)
			'''
			# 补充(装饰器语法糖):
				fbv,局部禁用csrf,如何写?
			    @csrf_exempt
			    def index(request):
			        pass
			    
			    本质原理是(装饰器本质):index=csrf_exempt(index)
			'''
            view=csrf_exempt(view)  # 局部禁用csrf,
            return view
        
  	-path('books/', View类的as_view中的view,只是去掉了csrf的认证)
	-请求来了,执行 【View类的as_view中的view,只是去掉了csrf的认证(request)-执行:self.dispatch(request, *args, **kwargs),  self要从根上找
	-self.dispatch 是APIView的dispatch,源码如下
        def dispatch(self, request, *args, **kwargs):
            # request 是新的request,      request是老的request
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            try:
                # 执行了认证,权限和频率
                self.initial(request, *args, **kwargs)
                # 在执行视图类方法之前,去掉了csrf认证,包装了新的request,执行了认证频率和权限
                #### 执行请求方式字符串对应的方法
                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
    

    
# 总结:
	1  以后只要继承APIView的所有视图类的方法,都没有csrf的校验了
    2  以后只要继承APIView的所有视图类的方法 中的request是新的request了
    3  在执行视图类的方法之前,执行了三大认证(认证,权限,频率)
    4  期间除了各种错误,都会被异常捕获,统一处理



总结

以上就是今天要讲的内容,本文仅仅简单介绍了 的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值