drf02

今日内容概要

  • RESTful规范
  • 序列化和反序列化
  • 基于django原生编写5个接口
  • drf介绍和快速入门
  • cbv源码分析

RESTful规范

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

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

  1. 数据的安全保障,通常使用

    https(http+ssl加密/tsl加密)协议

    url链接一般都采用https协议进行传输

    采用https协议,可以提高数据交互过程中的安全性

  2. 接口中带有api标识

    https://api.lqz.com/books

    https://www.lqz.com/api/books

    用第二个

  3. 多版本共存,路径中带版本信息

    https://api.lqz.com/v1/login

    https://www.lqz.com/api/v2/login

  4. 数据即是资源,均使用名词,尽量不出现动词(最核心的)

    接口一般都是完成前后台数据的交互,交互的数据我们称之为资源

    接口形式如下

    https://api.baidu.com/users

    https://api.baidu.com/books

    特殊的接口可以出现动词,因为这些接口一般没有一个明确的资源,或者动词就是接口的核心含义

    如: https://api.baidu.com/login

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

    操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查的动作

    https://api.baidu.com/booksget请求:获取全部图书

    https://api.baidu.com/books/1get请求:获取主键为1的图书

    https://api.baidu.com/bookspost请求:新增一本图书

    https://api.baidu.com/books/1put请求:修改主键为1的图书

    https://api.baidu.com/books/1delete请求:删除主键为1的书

  6. 在请求地址中带过滤条件

    https://api.baidu.com/books?name=红&price=99

    可以理解为查询图书名称带且价格为99的图书

    比如我们写的侧边栏。

  7. 响应状态码:两套

    http响应状态码:

    1xx : 请求正在处理,

    2xx: 成功响应 见最多的就是

    ​ -200(成功)服务器已成功处理了请求。通常,这表示服务器提供

    了请求的网页。

    ​ -201(已创建)请求成功并且服务器创建了新的资源。

    3xx: 重定向 301 永久重定向 302,307 临时重定向

    4xx: 客户端报错 403 没有权限 404 访问的地址不存在

    5xx: 服务端报错

    ​ -503(服务不可用)服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。

    第二套

    公司内部规定的响应状态码,放在响应体中

    {"code":0} 咱们后期一般使用100 101 102 这种

  8. 返回数据中带错误信息

  9. 返回的结果应该符合以下规范(好多公司不遵循这个)

    1. GET获取所有数据:返回资源对象的列表(数组)

      [{name:红楼梦,price:99},{name:红楼梦,price:99},{name:红楼梦,price:99}]
      
    2. GET单个对象:返回单个资源对象

      {name:红楼梦,price:99}
      
    3. POST新增对象:返回新生成的资源对象

      {name:西游记,price:99}
      
    4. PUT修改对象:返回完整的资源对象

      {name:西游记,price:100}
      
    5. DELETE删除对象:返回一个空文档

  10. 响应数据中带链接

序列化与反序列化

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

  • 序列化:把我们识别的数据转换成指定的格式提供给别人

    字典,列表 json格式存到文件中了

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

    当我们读数据的时候,把数据从数据库中把数据读出来

    然后把数据序列化成json格式字符串然后发送到前端

    我们一般把读数据就是序列化操作

  • 反序列化:把别人提供的数据转换/还原成我们需要的格式

    例如:前端js提供的json数据,对于python来说就是字符串,我们需要进行反序列化,才能把数据保存到数据库中

    当我们写数据,前端发送过来的数据,前端发送的数据就是字符串

    我们需要把字符串反序列化成数据能保存的数据。

    我们一般把写数据就是反序列化

drf介绍和快速使用

djangorestframework: drf 帮助我们快速的实现符合resstful规范的接口

django 最新 4.x , 一般都会用最新版的上一版的稳定版3.x

drf最新支持到django 3.x 最新的不支持django2.x

安装dirf

pip3 install djangorestframework

由于你是django2.x 它发现它不支持,它会自动卸载django,安装最新的django4.x

使用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),
]
# 两个列表相加  [1,2,4] +  [6,7,8]=
urlpatterns += router.urls


在 settings中

'rest_framework' # 注册drf这个app,如果不注册用浏览器访问会报错,如果注册了,用浏览器访问能看到好看的页面,不仅仅是json格式的数据

不注册会报错

注册了

cbv源码分析

as_view()入手

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

作业

新增图书,三种编码格式都能增加成功,django原生5个接口

model层

class Book(models.Model):
    name = models.CharField(max_length=32, verbose_name="书名")
    price = models.CharField(max_length=12, verbose_name="价格")
    publish = models.CharField(max_length=12, verbose_name="出版社名称")

    class Meta:
        verbose_name_plural = "图书表"

    def __str__(self):
        return "图书%s对象" % self.name

url层

path('books/', views.BooksView.as_view()),
path('books/<int:pk>/', views.Books2View.as_view())

view层

from .models import Book
from django import views
from django.http import JsonResponse
import json
from json import JSONDecodeError


class BooksView(views.View):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        book_obj = BooK()
        self.file_list = [i for i in book_obj.__dict__ if not i.startswith('_')]

    def get(self, request):
        book_queryset = Book.objects.all()
        book_list = []
        for book in book_queryset:
            book_list.append({book_file: getattr(book, book_file) for book_file in self.file_list})
        return JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii': False})

    def post(self, request):
        bank_data = {'code': 10000, "msg": '', "error": {}}
        res_dict = {}
        try:
            book_data = request.POST if request.POST else json.loads(request.body)
        except JSONDecodeError as e:
            bank_data['msg'] = '什么都没写'
        else:
            # 删除字段 id
            self.file_list.remove('id')
            # 循环出所有字段
            for book_file in self.file_list:
                # 判断前端传过来的字段是否完整, 不完整则提示它字段为空
                if not book_data.get(book_file):
                    bank_data['error'][book_file] = '字段%s为空' % book_file
                else:
                    res_dict[book_file] = book_data.get(book_file)
            # 判断字段时候有为空的 如果有不为空则添加
            if not bank_data.get('error'):
                Book.objects.create(**res_dict)
                bank_data['data'] = res_dict
                bank_data['msg'] = '添加成功'
            else:
                bank_data['code'] = 10001
                bank_data['msg'] = '添加失败'
        return JsonResponse(bank_data, json_dumps_params={'ensure_ascii': False})


class Books2View(views.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        book_obj = Book.objects.first()
        self.file_list = [i for i in book_obj.__dict__ if not i.startswith('_')]

    def get(self, request, pk):
        book_obj = Book.objects.filter(pk=pk).first()
        data = {book_file: getattr(book_obj, book_file) for book_file in self.file_list}
        return JsonResponse(data)

    def put(self, request, pk):
        book_obj = Book.objects.filter(pk=pk).first()
        # put 请求的POST和GET都取不到, 所以只能在body里面取
        book_data = json.loads(request.body)
        print(book_data)
        for book_file in self.file_list:
            setattr(book_obj, book_file, book_data.get(book_file, getattr(book_obj, book_file)))
        book_obj.save()
        print(book_obj.name)
        data = {book_file: getattr(book_obj, book_file) for book_file in self.file_list}
        return JsonResponse(data)

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return JsonResponse({})

使用ajax提交到后台数据

ajax     
		urlencoded
		form-data
		json

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'js_dir/jquery-1.12.4.js' %}"></script>
    <script src="{% static 'js_dir/sweelalert.js' %}"></script>
</head>
<body>
<button id="btn1">普通数据</button>
<input type="file" id="file">
<button id="btn2">文件数据</button>
<button id="btn3">Json数据</button>

<script>
    $('#btn1').click(function () {
        $.ajax({
            url: '/aaa/',
            type: 'post',
            data: {"name": "jason"},
            success: function (args) {
                swal(args.msg)
            }
        })
    })
    $('#btn2').click(function () {
        let formData = new FormData()
        formData.append("file", $('#file')[0].files[0])
        $.ajax({
            url: '/aaa/',
            type: 'post',
            data: formData,
            contentType: false,
            processData: false,
            success: function (args) {
                swal(args.msg)
            }
        })
    })
    $('#btn3').click(function () {
        $.ajax({
            url: '/aaa/',
            type: 'put',
            data: JSON.stringify({"name": "jason"}),
            contentType: "application/json",
            success: function (args) {
                swal(args.msg)
            }
        })
    })
</script>
</body>
</html>

view层

def aa_func(request):
    bank_data = {'msg': ''}
    if request.method == 'POST':
        bank_data['msg'] = request.POST.get('name')
        if not bank_data.get('msg'):
            file = request.FILES.get('file')
            res = len(file)
            bank_data['msg'] = str(res)
        return JsonResponse(bank_data)
    elif request.method == 'PUT':
        bank_data['msg'] = json.loads(request.body).get('name')
        return JsonResponse(bank_data)
    return render(request, 'content.html')
posted @ 2023-01-31 21:50  可否  阅读(50)  评论(0编辑  收藏  举报