Django之drf

一、restful规范

1、概念

​ REST全称是Representational State Transfer,中文意思是表述:表征性状态转移,它首次出现在2000年Roy Fielding的博士论文中。

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

2、REST的十个规范

在这里插入图片描述

数据的安全保障

  • 通常使用https(http+ssl/tsl)协议
    • url链接一般采用https协议进行传输
    • 采用https协议,可以提高数据交互过程中的安全性

接口中带api标识

路径中带版本信息

数据即是资源,均使用名词,避免动词(核心)

资源操作由请求方式决定(method)

请求地址中带过滤条件

响应中状态码:两套

  • web服务自带状态码
    • 1xx:请求正在处理
    • 2xx:成功
    • 3xx:重定向
    • 4xx:客户端错误
    • 5xx:服务端错误
  • 公司内部规定的状态码,放在响应体中
    • 一般使用1000往后的状态码

返回的数据中带错误信息

  • {
    code:0
    msg: "ok/用户名错误"
    }

返回的结果遵循以下规范

  • GET 获取所有数据:返回资源对象的列表(数组)
  • GET 单个对象:返回单个资源对象
  • POST 新增对象:返回新生成的资源对象
  • PUT 修改对象:返回完整的资源对象
  • DELETE 删除:返回一个空文档

响应数据中带链接

  • 即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

img

二、序列化、反序列化

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

序列化

把我们识别的数据转换成指定的格式提供给别人

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

反序列化

把别人提供的数据转换/还原成我们需要的格式。

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

img

三、drf介绍及快速使用

1、基于django原生编写5个接口

# 以后所写的接口,基本上都是5个接口及其变形
    -查询所有
    -查询单个
    -新增一个
    -修改一个
    -删除一个
    
# 基于books单表为例,写5个接口
    -创建book表
    -表迁移
    -录入假数据:直接录,后台管理录
    -写查询所有接口---》遵循restful规范,使用cbv
    -新增一个数据
    -查询一个
    -修改一个:put提交的数据,不能从requets.POST中取
    -删除一个
 
import json

from django.shortcuts import render

# Create your views here.
from django.views import View
from .models import Books
from django.http import JsonResponse


class BookViews(View):
    def get(self, request):
        book_all_queryset = Books.objects.all()
        book_data_list = [{'name': book_queryset.name,
                           'price': book_queryset.price,
                           'publish': book_queryset.publish}
                          for book_queryset in book_all_queryset]
        return JsonResponse(book_data_list, safe=False, json_dumps_params={'ensure_ascii': False})

    def post(self, request):
        new_book_obj = Books.objects.create(name=request.POST.get('name'),
                                            price=request.POST.get('price'),
                                            publish=request.POST.get('publish'))
        new_book_dict = {
            'name': new_book_obj.name,
            'price': new_book_obj.price,
            'publish': new_book_obj.publish
        }
        return JsonResponse(new_book_dict, safe=False, json_dumps_params={'ensure_ascii': False})


class BookViews_1(View):
    def get(self, request, pk):
        book_queryset = Books.objects.filter(pk=pk).first()
        if book_queryset:
            book_data_dict = {
                'name': book_queryset.name,
                'price': book_queryset.price,
                'publish': book_queryset.publish
            }
            return JsonResponse(book_data_dict, safe=False, json_dumps_params={'ensure_ascii': False})
        return JsonResponse({'msg': '查询失败!无指定编号!'})

    def put(self, request, pk):
        target_book_queryset = Books.objects.filter(pk=pk).first()
        if target_book_queryset:
            book_data_dict = json.loads(request.body)
            target_book_queryset.name = book_data_dict.get('name')
            target_book_queryset.price = book_data_dict.get('price')
            target_book_queryset.publish = book_data_dict.get('publish')
            target_book_queryset.save()

            book_data_dict = {
                'name': target_book_queryset.name,
                'price': target_book_queryset.price,
                'publish': target_book_queryset.publish
            }
            return JsonResponse(book_data_dict, safe=False, json_dumps_params={'ensure_ascii': False})
        return JsonResponse({'msg': '修改失败!无指定编号!'})

    def delete(self, request, pk):
        target_book_queryset = Books.objects.filter(pk=pk)
        if target_book_queryset:
            target_book_queryset.delete()
            return JsonResponse({})
        return JsonResponse({'msg':'删除失败!无指定编号!'})
import json

from django.shortcuts import render

# Create your views here.
from django.views import View
from .models import Books
from django.http import JsonResponse


class BookViews(View):
    def get(self, request):
        book_all_queryset = Books.objects.all()
        book_data_list = [{'pk': book_queryset.pk,
                           'name': book_queryset.name,
                           'price': book_queryset.price,
                           'publish': book_queryset.publish}
                          for book_queryset in book_all_queryset]
        return JsonResponse(book_data_list, safe=False, json_dumps_params={'ensure_ascii': False})

    def post(self, request):
        new_book_obj = Books.objects.create(name=request.POST.get('name'),
                                            price=request.POST.get('price'),
                                            publish=request.POST.get('publish'))
        new_book_dict = {
            'name': new_book_obj.name,
            'price': new_book_obj.price,
            'publish': new_book_obj.publish
        }
        return JsonResponse(new_book_dict, safe=False, json_dumps_params={'ensure_ascii': False})


class BookViews_1(View):
    def get(self, request, pk):
        book_queryset = Books.objects.filter(pk=pk).first()
        if book_queryset:
            book_data_dict = {
                'name': book_queryset.name,
                'price': book_queryset.price,
                'publish': book_queryset.publish
            }
            return JsonResponse(book_data_dict, safe=False, json_dumps_params={'ensure_ascii': False})
        return JsonResponse({'msg': '查询失败!无指定编号!'})

    def put(self, request, pk):
        target_book_queryset = Books.objects.filter(pk=pk).first()
        if target_book_queryset:
            book_data_dict = json.loads(request.body)
            setattr(target_book_queryset, 'name', book_data_dict.get('name'))
            setattr(target_book_queryset, 'price', book_data_dict.get('price'))
            setattr(target_book_queryset, 'publish', book_data_dict.get('publish'))
            # target_book_queryset.name = book_data_dict.get('name')
            # target_book_queryset.price = book_data_dict.get('price')
            # target_book_queryset.publish = book_data_dict.get('publish')
            target_book_queryset.save()

            book_data_dict = {
                'name': target_book_queryset.name,
                'price': target_book_queryset.price,
                'publish': target_book_queryset.publish
            }
            return JsonResponse(book_data_dict, safe=False, json_dumps_params={'ensure_ascii': False})
        return JsonResponse({'msg': '修改失败!无指定编号!'})

    def delete(self, request, pk):
        target_book_queryset = Books.objects.filter(pk=pk)
        if target_book_queryset:
            target_book_queryset.delete()
            return JsonResponse({})
        return JsonResponse({'msg': '删除失败!无指定编号!'})

2、drf的使用

​ drf全称:djangorestframework,能够帮助我们快速实现符合restful规范的接口

版本及安装

  • 版本说明:

    • django当前最新版本4.x
    • drf最新支持到django3.x,最新不支持2.x
  • 安装:

    • 我们使用的django版本为2.x,在安装drf后会自动将django升级到最新版本,如果dango版本是3.x就不会出现自动更新的情况,只需在安装drf重新装会2.x版本即可
    • pip3 install djangorestframework -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com/simple/

3、drf编写5个接口

# 使用drf编写5个接口(听个响)

# 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),
]
# 两个列表相加
urlpatterns += router.urls

四、CBV源码刨析

# 1 路由中写的:path('api/v1/books/', views.BookView.as_view()),第二个参数无论是fbv还是cbv放的都是函数内存地址
	-当请求来了,匹配成功会执行,views.BookView.as_view()(request)
    -views.BookView.as_view()执行结果是View的类方法as_view返回的结果是内层函数view,是个函数内层地址
    -本身请求来了,匹配成功,会执行view(request)
    def view(request, *args, **kwargs):
        return self.dispatch(request, *args, **kwargs)
    
    -self.dispatch  View类的方法
   	def dispatch(self, request, *args, **kwargs):
        # request.method请求方式转成小写,必须在列表中才能往下走
        if request.method.lower() in self.http_method_names:
            # 反射,去self【视图类的对象:BookView】,去通过get字符串,反射出属性或方法
            # BookView的get方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        # BookView的get方法,加括号,传入request
        return handler(request, *args, **kwargs)