文章目录

  • 1. Web应用模式
    • 1.1 动/静态页面
    • 1.2 前后端不分离
    • 1. 3前后端分离
    • 1.4 JSON/XML数据格式
      • 1. json格式
      • 2. xml格式
    • 1.5 服务器页面后缀
  • 2. API接口
    • 2.1 由来
    • 2.2 特点
  • 3. Portman
    • 3.1 下载
    • 3.2 安装
    • 3.3 建立连接
    • 3.4 导出与导入
      • 1. 导出
      • 2. 导入
  • 4. Restful规范
    • 4.1 简介
    • 4.2 规范
  • 5. DRF安装与使用
    • 5.1 安装
    • 5.2 使用
    • 5.3 Postman连接
      • 1. 查
      • 2. 删
      • 3. 改
      • 4. 增
  • 6. Dajngo View源码解析
  • 7. DRF APIView源码解析
  • 8. DRF Request类
  • 9. 读源码总结
  • 10 练习
    • 10.1 创建环境
    • 10.2 增
    • 10.3 查
    • 10.3 改
    • 10.5 删

1. Web应用模式

在开发Web应用中有两种应用模式:
1. 前后端不分离(混合开发), 需要写模板, 页面的渲染在服务器上完成.
2. 前后端分离, 只专注于写后端接口, 返回JSON/XML数据, 页面的渲染在浏览器完成.

1.1 动/静态页面

动态页面: 显示的内容却是可以随着时间, 环境或者数据库操作的结果而发生改变的.
静态页面: , 无需经过服务器的编译, 直接加载到客户浏览器上显示出
静态页面因为不需要而外的操作, 所有请求速度快.
大型的网站首页, 会将动态的页面静态化, 不需要每次都查询数据库, 当数据发生了变化之后再次生成一个静态页面.

1.2 前后端不分离

用户发送请求后得到的是模板语法渲染后的HTML页面.

1. 3前后端分离

用户第一次访问的时候, 被另一个静态文件服务接收, 并放回一个静态页面.
之后再基于静态页面的js代码向服务器发送请求, 服务返回页面渲染需要的数据, 静态页面拿到数据后渲染.

1.4 JSON/XML数据格式

json格式占用的资源比xml少.
1. json格式
* json使用的双引号
{"name":"kid"}
2. xml格式
<xml><name>kid</name>
</xml>

1.5 服务器页面后缀

根据请求内容动态地生成HTML, XML或其他格式文档的Web网页, 返回给用户,
部分编程语言使用的框架返回的页面会携带一个标识后缀.
java --> jsp
https://xxx.xxx.xxx/xxx.jsp
php  --> php
http://xxx.xxx.xxx/xxx.php
Python --> 没有
http://xxx.xxx.xxx/xxx

2. API接口

API接口: 规定前后端信息交互规则. 通过Web通信, 也被称为Web API.

2.1 由来

为了形成共识, 防止个人习惯引起的混乱, 需要一套统一的接口规范, 能让前后端写的接口用途一目了然.

2.2 特点

* 1. url长得像返回数据的url链接eg: 百度的api: http://api.map.baidu.com/place/v2/search
* 2. 请求方式: get, post, put, path, delete
* 3. 请求参数: json或xml格式的key-value类型数据
* 4. 响应结果: json或xml的数据
在浏览器中输入: http://api.map.baidu.com/place/v2/search 返回百度地址的API接口
AK参数是自定义的token

携带参数进行访问:
AK=6E823f587c95f0148c19993539b99295
region=上海
query=肯得基
output=json
http://api.map.baidu.com/place/v2/search?ak=1A43B68F2A55B3A07EB09E3B8303E5:FG=1&region=上海&query=肯得基&output=json

3. Portman

Postman是一个用于构建和使用API的API平台. 支持用户实时发送HTTP网页请求, 帮助用户更好地搭建应用程序,
提高程序开发效率, 同时软件内置了测试语言脚本, 支持用户自定义测试脚本使用.

3.1 下载

* 1. 下载地址: https://www.Postman.com/

* 2. 点击下载

3.2 安装

* 1. 双击安装, 没有配置可以选择.默认安装在 C:\Users\用户\AppData\Local\Postman

* 2. 进入软件界面

3.3 建立连接

* 1. 新建请求

* 2. 选择请求方式

* 3. 请求参数 请求头 请求体的设置

* 4. 新建一个收藏目录

* 5. 在目录下添加请求

* 6. 收藏目录具备的功能没有可用的API就不测试运行了

3.4 导出与导入

在测试的时候可以将请求收藏目录导出成一个文件, 可以将文件发给自己合作伙伴, 对方将文件导入即可使用.
1. 导出
* 1. 导出请求文件

* 2. 选择位置保存

2. 导入
* 3. 选择导入

* 2. 选择上传文件

* 3. 找到文件, 点击确定

* 4. 导入预览, 点击导入

* 5. 导入成功

4. Restful规范

4.1 简介

REST: 全称Rpsentaional State Transfer, 表特征状态转移.
Restful 是一种定义Web API接口的设置风格, 适用于前后端分离的应用模式.
可以在任何框架实现符合Restful规范的API接口.

4.2 规范

Restful拥有10条规范:
* 1. 数据安全保障: url链接一般采用https协议进行传输. https可以提高数据交互过程中的安全性.http 和 不加密的json格式被抓包工具(fiddler, charles...)捕获数据后很容易被解析出来.
* 2. 接口的特征表现: 一看就知道是API接口https://api.baidu.comhttps://www.baidu.com/api在路由或域名中携带api字眼
* 3. 多数据版本共存: 项目后续可能升级, 之前的API接口, 某些客户端可能在使用, 另外开设API接口.在url链接中标识数据的版本: https://api.baidu.com/v1https://api.baidu.com/v2url链接v1, v2就是不同数据版本的体现, 只有在获取同一种资源下有多版本的情况.
动词不使用, 但利用请求方式去描述了需要操作的动词.
* 4. 数据及资源, 路径均使用名称(一般提倡资源使用复数形式)接口一般都是完成前后端数据的交互, 交互的数据称之为资源https://api.baidu.com/usershttps://api.baidu.com/books在url链接中, 尽量不要出来资源的动词, eg: get_books, del_books...特殊的接口可以出现动词, 这些接口没有明确的资源, 或这个动词就是接口的核心含义.https://api.baidu.com/place/searchhttps://api.baidu.com/login
* 5. 资源操作由请求方式决定(method)操作资源一般都会涉及增删改查, 通过不同的请求方式来标识这些动作.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/    post请求:   修改主键为1的书籍https://api.baidu.com/books/1   put请求:    整体修改主键为1的书籍https://api.baidu.com/books/1   patch请求:  局部修改主键为1的书籍https://api.baidu.com/books/1   delete请求: 删除主键为1的书籍
* 6. 过滤, 通过在url中传递参数的形式, 携带搜索条件https://ap1.xxx.com/v1/books?limit=10   指定返回数据的数量https://ap1.xxx.com/v1/books?offset=10  指定返回记录的开始位置, (获取了10条数据, 再向前偏移10)https://ap1.xxx.com/v1/books?page=2&per_page=100 指定第几页, 以及每条的记录数https://api.xxx.com/v1/books?sortby=name&order=asc 指定返回结果安装哪个属性排序, 及排序方式https://ap1.xxx.com/v1/books?book_id=1  指定筛选条件
* 7. 响应状态码正常响应: 响应状态码2xx200 常规请求201 创建数据成功重定向响应: 响应状态码3xx301 永久重定向302 展示重定向客户端异常: 响应状态码4xx403 请求无权限404 请求路径不存在405 请求路径存在,但是请求的方法不存在服务器异常:响应状态码5xx500 服务器异常
* 8. 错误处理, 因该放回错误信息, error作为key{error: '无权限操作!'}
* 9. 返回结果, 针对不同的操作, 服务器想用户返回非结果符合以下规范:GET  /books     返回资源对象的列表或者数组GET  /books/1   返回单个资源对象POST /books     返回新生成的对象资源PUT  /books/1   返回完整的资源对象PATCH /books/1  返回完整的资源对象DELETE /books/1 返回一个空文档
* 10. 需要url请求的资源, 需要返回资源的请求资源返回结果在家哦你提供链接, 连向其他API方法, 使得用户不查文档, 也知道下一步需要做什么{"code": 200,"msg": "ok","results: [{"name": "开局签到荒古圣体","img": "https://image.novels.com/books/cover.png"}...]}

5. DRF安装与使用

全称: djangorestframework 是基于Django框架, 用于快速构建Web Restful API的工具.
新建一个Django项目, 模板目录路径报错问题.

5.1 安装

使用3.10.3版本
pip3.6 install djangorestframework==3.10.3

5.2 使用

* 1. 项目配置文件的INSTALLED_APPS属性中注册rest_framworh
    # 注册drf'rest_framework',
* 2. 在app01下的models.py文件中创建一个映射表关系的类
from django.db import models# Create your models here.# 0. 书籍表
class Book(models.Model):# 0.1 id自定生成# 0.2 书的名称title = models.CharField(max_length=32, verbose_name='书名')# 0.3 书的价格 共5位小数占两位price = models.DecimalField(max_digits=5, decimal_places=2)# 0.4 作者author = models.CharField(max_length=32, verbose_name=32)
* 3. 生成表1. 生成表记录:  python3.6 manage.py makemigrations2. 数据库迁移命令: python3.6 manage.py migrate
* 4. 在tests.py测试文件中 写入两条数据import os
import sysif __name__ == "__main__":os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_drf_01.settings")import djangodjango.setup()from app01.models import Book# 批量插入数据# 1. 定义空一个列表queryset_list = []#  2. 写入的数据data_list = [{'title': '开局签到荒古圣体', 'price': 123.12, 'author': 'kid'},{'title': '开局签到五费卡', 'price': 321.21, 'author': 'qq'}]# 3. 生成对象并添加到列表中for dic in data_list:book_obj = Book(**dic)queryset_list.append(book_obj)# 4. 批量插入数据Book.objects.bulk_create(queryset_list)

不想敲代码就手动输入
Navicat 快速打开sqlite3的文件

* 4 . 在应用app01下创建一个ser.py 文件 序列化表
# 0. 导入模型序列化器
from rest_framework.serializers import ModelSerializer
# 1. 带入表
from app01.models import Book# 定义一个模型序列化器
class BookModelSerializer(ModelSerializer):# 定义元类class Meta:# 需要转换的表model = Book# 需要转换的字段 所有fields = "__all__"
* 5. 写地址book的路由
from django.conf.urls import url
from django.contrib import admin
# 0. 导入视图层
from app01 import views
# 1. 导入 默认路由器
from rest_framework.routers import DefaultRouter# 2. 生成一个路由对象 --> list
router = DefaultRouter()
print(router)
# 3. 注册一个路由
router.register('books', views.BooksViewSet)urlpatterns = [url(r'^admin/', admin.site.urls),
]
* 5. 写BooksViewSet的视图函数
# 0. 导入模型视图集
from rest_framework.viewsets import ModelViewSet
# 1. 导入模型层
from .models import Book
# 2. 导入模型序列化器
from .ser import BookModelSerializer# 3. 定义视图函数
class BooksViewSet(ModelViewSet):# 查询表所有的数据queryset = Book.objects.all()# 查询表所有的数据并序列化serializer_class = BookModelSerializer
class BooksViewSet(ModelViewSet):
ModelViewSet 继承 GenericViewSet 继承 views.APIView 继承 View
* 6. 启动Django在浏览器中输入 127.0.0.1:8000

* 7. 在浏览器中输入 127.0.0.1:8000/books 或点击上图中的返回链接, 返回含义json格式数据的页面.127.0.0.1:8000/books/1 查询主键为1书籍的信息127.0.0.1:8000/books/2 查询主键为2书籍的信息

5.3 Postman连接

部分起你去Postman可能不支持重定向操作, 就手动在后面加上/
Django让请求端加/后再次请求, Django能操作浏览的url, 操作不动Postman...
1. 查
提交post请求返回json格式的数据
127.0.0.1:8000/books/
127.0.0.1:8000/books/1/
127.0.0.1:8000/books/2/

2. 删
提交delete请求, 删除数据返回空
127.0.0.1:8000/books/1/

3. 改
提交put请求, 返回数据对象
提交数据选择body, 点击raw, 选择JSON格式数据
127.0.0.1:8000/books/2/
{"id": 2,"title": "开局签到金克斯","price": "12.30","author": "qq"
}

返回的信息

4. 增
提交post请求, 返回新增的对象
提交数据选择body, 点击raw, 选择JSON格式数据
127.0.0.1:8000/books/
{"title": "Python入门到放弃","price": "66.6","author": "kid"
}

6. Dajngo View源码解析

CBV视图类必须继承View
Python下载的模块Python的lib/site-packages下
在看源码的时候可以打开展示组成部分, 代开之后, py文件可以展示函数, 类..
在源码中会看见一些函数名点属性的情况, 那么在这说明一下, Python中一切皆对象,
只要对象有.__setattr__方法就可以拥有属性, 即可以存储值, 那么对象有.__getattr__便可以取值.
def func2():passfunc2.x = 1
print(type(func2), func2.x)  # <class 'function'> 1"""
func即是函数内存地址也是一个function类,
func.属性 = 值
.属性会执行类中__setattr__方法, 函数是由关键字def构建的, 这个__setattr__方法无法看见
只需要知道可以这样操作即可
"""
查看源码先将展示组成部分打开, 方便查找.

* 1. 写一个路由
    # 写一个路由url(r'^books2/', views.Books2.as_view()),
* 2. 视图类
# 4. 导入Vies类
from django.views import View
# 5. 导入HttpResponse
from django.shortcuts import HttpResponse# 6. 定义视图类
class Books2(View):# 6.1定义get方法def get(self, request):# 6.2 返回响应return HttpResponse('OK')
url(r'^books2/', views.Books2.as_view())
url的第二个参数是一个函数的内存地址,
那么Books2.as_view执行之后肯定得到一个函数的内存地址.
在Books2中没有写.as_view方法, 那么就去父类中查找, 父类View中有该方法.
View文件所在文件:
C:\Users\用户名\AppData\Roaming\Python\Python36\site-packages\django\views\generic\base.py
class classonlymethod(classmethod):...
# classonlymethod继承了classmethod, 在它的基础上添加了方法@classonlymethod
def as_view(cls, **initkwargs):...
# as_view就是一个类方法, 给类使用, 将类名作为一个参数自动传递.

url(r'^books2/', view(request))
路由匹配成功的时候, 函数内存地址会加括号执行, 并把request作为第一个参数进行传递
def view(request, *args, **kwargs):# request 是当前请求的数据# cls是Books2, 得到一个Books2的对象self = cls(**initkwargs)# hasattr反射, 如果对象中用get方法 and 没有head方法if hasattr(self, 'get') and not hasattr(self, 'head'):# 对象的head属性 = self的getself.head = self.get# 对象的request属性 = request请求数据self.request = request# 对象的args属性接收所有位置参数self.args = args# 对象的**kwargs属性接收所有的关键字参数self.kwargs = kwargs# 对象的dispatch加括号执行, 自己写的Books2类中没有改方法就去父类中查找return self.dispatch(request, *args, **kwargs)
父类中有dispath方法

# 对象.方法将对象作为第一参数进行传递
def dispatch(self, request, *args, **kwargs):# Try to dispatch to the right method; if a method doesn't exist,# defer to the error handler. Also defer to the error handler if the# request method isn't on the approved list.# 判断当前的请求方式, 转小写 是否在对象的http_method_names属性中if request.method.lower() in self.http_method_names:# 如果存在就通过反射拿到这个方法的内置地址# 自己没有在类中定义就无法获取数据, 返回默认值, 抛出一个错误信息,请求方法不允许.handler = getattr(self, request.method.lower(), self.http_method_not_allowed)else:# 请求不方式不在对象的http_method_names属性中, 抛出一个错误信息,请求方法不允许.handler = self.http_method_not_allowed# 获取到到当前请求方法对应的方法加括号执行return handler(request, *args, **kwargs)
父类中有http_method_names属性

http_method_names 在自己写的类中定义的话可以对请求进行限制.
执行了方法之后, 开始返回数据.

7. DRF APIView源码解析

APIView是rest_framework的
导入 from rest_framework.views import APIView
* 1. 定义一个路由
    # 写一个路由 查看APIvies源码url(r'^books3/', views.Books3.as_view()),
* 2. 定义视图类
# 7. 导入 APIView
from rest_framework.views import APIView# 8. 定义视图类Books3
class Books3(APIView):# 8.1 定义get方法def get(self, request):# 8.2 返回响应return HttpResponse('OK')
url(r'^books3/', views.Books3.as_view())
那么Books3.as_view执行之后肯定得到一个函数的内存地址.
在Books2中没有写.as_view方法, 那么就去父类中查找, 父类APIView中有该方法.
APIView的中有通过super().as_view(**initkwargs)去拿到View的as_view方法, 得到一个view函数的内存地址.
class APIView(View):...@classmethoddef as_view(cls, **initkwargs):# 这句不看if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):...# 调用父类View的as_view方法, 该方法返回一个 view的内置地址 view = super().as_view(**initkwargs)# 记录参数view.cls = clsview.initkwargs = initkwargs# 添加禁用csrf检验的装饰器, 看下下return csrf_exempt(view)
局部禁用csrf检验在函数上加@csrf_exempt
@csrf_exempt  # ==> csrf_exempt(func)
def func(request):...
还有一种写法, 在路由中局部添加禁用csrf装饰器
# views.test是一个函数的内存地址, csrf_exempt(函数内存地址) 为函数加上装饰器
from django.views.decorators.csrf import csrf_exempt
url('^test/', csrf_exempt(views.test)),
APIView文件所在位置:
D:\Python\Python3.6\Lib\site-packages\rest_framework\views.py

只要继承了APIView, 执行as_views(), 在父类的基础上添加了添加scrf_exempt装饰器去除csrf检验
拿到vies函数名后加括号调用
vies() --> View的执行as_views的vies函数
def view(request, *args, **kwargs):# 类名加括号, 生成一个books3对象self = cls(**initkwargs)# 判断对象是都有get方法 and 没有head方法if hasattr(self, 'get') and not hasattr(self, 'head'):...这里没什么不看了...# 对象执行dispatch方法return self.dispatch(request, *args, **kwargs)
Books3中没有dispatch方法去父类APIView中查找
def dispatch(self, request, *args, **kwargs):"""`.dispatch()` is pretty much the same as Django's regular dispatch,but with extra hooks for startup, finalize, and exception ha    ndling."""self.args = argsself.kwargs = kwargs#  self.initialize_request(request, *args, **kwargs), 中request是当前请求的#  request 是执行对象的initialize_request重新包装的request, # 对象中没有initialize_request方法去父类中APIView中查找request = self.initialize_request(request, *args, **kwargs)# 将数据保存self.request = requestself.headers = self.default_response_headers  # deprecate?try:# 三大认证模块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# 获取到请求方法之后加括号调用, 将重新包装的request传递进去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

8. DRF Request类

看下initialize_request是怎么样包装request的
def initialize_request(self, request, *args, **kwargs):# 解析器上下文parser_context = self.get_parser_context(request)# 通过执行Request包装的return Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)
class Request:"""Wrapper allowing to enhance a standard `HttpRequest` instance.Kwargs:- request(HttpRequest). The original request instance.- parsers_classes(list/tuple). The parsers to use for parsing therequest content.- authentication_classes(list/tuple). The authentications used to tryauthenticating the request's user."""def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):assert isinstance(request, HttpRequest), ('The `request` argument must be an instance of ''`django.http.HttpRequest`, not `{}.{}`.'.format(request.__class__.__module__, request.__class__.__name__))self._request = requestself.parsers = parsers or ()self.authenticators = authenticators or ()self.negotiator = negotiator or self._default_negotiator()self.parser_context = parser_contextself._data = Emptyself._files = Emptyself._full_data = Emptyself._content_type = Emptyself._stream = Emptyif self.parser_context is None:self.parser_context = {}self.parser_context['request'] = selfself.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSETforce_user = getattr(request, '_force_auth_user', None)force_token = getattr(request, '_force_auth_token', None)if force_user is not None or force_token is not None:forced_auth = ForcedAuthentication(force_user, force_token)self.authenticators = (forced_auth,)
APIView文件所在位置:
D:\Python\Python3.6\Lib\site-packages\rest_framework\request.py

# 7. 导入 APIView
from rest_framework.views import APIView# 8. 定义视图类Books3
class Books3(APIView):# 8.1 定义get方法def get(self, request):# 查询request对象print(request, request._request)# <rest_framework.request.Request object at 0x000001BE69EBB5C0>  Request重新封装的# <WSGIRequest: GET '/books3/'>  WSGI封装的原始Request# 8.2 返回响应return HttpResponse('OK')
那么使用request的方法会是怎么样的
没有不要这样去写 request._request.method
# 8. 定义视图类Books3
class Books3(APIView):# 8.1 定义get方法def get(self, request):  print(request.method)  # GET# 8.2 返回响应return HttpResponse('OK')
被包装request有.属性那么可能写了__getattr__方法
def __getattr__(self, attr):try:return getattr(self._request, attr)# 如果取不出来在通过另一种反法再取except AttributeError:return self.__getattribute__(attr)

Request类将所有的post请求数据都封装到data属性中.
# 7. 导入 APIView
from rest_framework.views import APIView# 8. 定义视图类Books3
class Books3(APIView):# 8.1 定义get方法def get(self, request):print(request.method)  # GET# 8.2 返回响应return HttpResponse('OK')# 8.3 定义post请求方法def post(self, request):print(request.data)# 8.4 返回响应return HttpResponse('OK')

data是一个静态方法

get请求,地址中的参数 request.query_params
print(request.GET)
# 7. 导入 APIView
from rest_framework.views import APIView# 8. 定义视图类Books3
class Books3(APIView):# 8.1 定义get方法def get(self, request):print(request.query_params)  # GET的请求数据# 8.2 返回响应return HttpResponse('OK')

APIView的initial方法
def initial(self, request, *args, **kwargs):# 认证组件:校验用户 - 游客、合法用户、非法用户# 游客:代表校验通过,直接进入下一步校验(权限校验)# 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)# 非法用户:代表校验失败,抛出异常,返回403权限异常结果self.perform_authentication(request)# 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色# 认证通过:可以进入下一步校验(频率认证)# 认证失败:抛出异常,返回403权限异常结果self.check_permissions(request)# 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)# 没有达到限次:正常访问接口# 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问self.check_throttles(request)

9. 读源码总结

CBV源码分析:1. 视图类, 必须继承Django的View类2. 类中支持多种请求方式, get, post, put, delete, ...请求来执行对应的方法3. Django程序执行到 views.类.as_views(), 立刻执行as_views()方法, 自己的类中没有去父类View中找4. 最后一个view闭包函数的内存地址5. 请求的路由匹配成功 view加括号调用, 并把第request作为第一个参数传入6. view(request) 执行 --> 通过闭包函数的特性拿到类名, 类名加括号生成一个对象, 对象.dispatch()7. 自己写的类没有.dispatch()方法去父类Django的View类中查找8. dispatch方法将请求转为小写, 在去判断请求是否在属性http_method_names列表中9. 自己写的类中没有http_method_names属性去父类Django的View类中查找10. 如果请求满足条件, 通过反射获取请求的方法 , 再加括号执行, 并且将request传入.
APIView源码解析:1. 视图类, 继承DRF的APIView, APIView继承Django的View2. 类中支持多种请求方式, get, post, put, delete, ...请求来执行对应的方法3. Django程序执行到views.类.as_views(), 立刻执行as_views()方法, 自己的类中没有去父类APIView中找4. APIView中as_views()继承Django的View类的as_views()方法, 得到一个view闭包函数在为这个闭包函数加上一个装饰器器去除csrf校验5. 请求的路由匹配成功 view加括号调用, 并把第request作为第一个参数传入6. view(request) 执行 --> 通过闭包函数的特性拿到类名, 类名加括号生成一个对象, 对象.dispatch()7. 自己写的类没有.dispatch()方法去父类DRF的APIView类中查找8. dispatch方法8.1 将request重新封装, 得到一个新的request8.2 异常捕获下面代码8.3 加上三大认证模块8.4 再将请求转为小写, 在去判断请求是否在属性http_method_names列表中自己写的类中没有                   http_method_names属性去父类DRF的APIView类中查找, 还没有则去Django的View中找8.5 如果请求满足条件, 通过反射获取请求的方法, 再加括号执行, 并且将重新封装的request传入.8.6 将对应请求方法执行的结果赋值给response8.7 将异常的结果赋值给response8.8 渲染模块, 浏览访问访问什么样的数据格式, Pastman访问返回什么样的数据* 注意点视图类的request是DRF的APIView类中的方法重新封装的, 使用方法与原来一模一样, 所有的post请求数据被封装到data属性中, 以字典的形式表示.

10 练习

新建一个图书表, 写5个符合restful规范的接口, 用CBV的APIView实现.

10.1 创建环境

* 1. 写路由
from django.conf.urls import url
from django.contrib import admin
# 导入视图层
from app01 import views
# 导入禁用csrf装饰器
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [url(r'^admin/', admin.site.urls),# 1.路由带api字眼, 2.路由的名字是名词最好是复数, 3.查询数据带版本号url(r'^api/books/v1/', scrf_exempt(views.Book.as_view()),
]
* 2. 写CBV视图类
from django.shortcuts import render
# 导入JsonResponse
from django.http import JsonResponse# Create your views here.
# 导入 View
from django.views import View# 导入 json模块
import json# 导入模板
from app01 import models# 写数图类, 继承View
class Book(View):# 定义五个方法 get, post, put, patch, delete# 查def get(self, request):pass# 增def post(self, request):pass# 局部修改def put(self, request):pass# 全局修改def patch(self, request):pass# 删除def delete(self, request):pass
* 3. 模型中写映射表关系的类
from django.db import models# Create your models here.# 书籍表 继承Model
class Book(models.Model):# 主键自动创建 非空且唯一 自增# 书名title = models.CharField(max_length=32, verbose_name='书名')# 数价格 共5位小数占2为price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='价格')# 作者author = models.CharField(max_length=32, verbose_name='作者')# 获取所有数据组织成一个字段def get_data(self):book_dict = {'id': self.id,'title': self.title,'price': float(self.price),  # 将Decimal转为float'author': self.author}return book_dict
* 4. 生成表生成操作记录 python manage.py makemigrations数据库迁移 python manage.py migrate

10.2 增

提交post请求, 创建成功之后返回单个数据对象
提交地址: 127.0.0.1:8000/api/books/v1
提交数据格式json: (id不需要提交, json格式数据是双引号)
{"title": "book1","price": 123.1,"author": "aa"
}
django中的request.POST只能取到Content-Type(请求头)为application/x-www-form-urlencoded(form表单默认格式)的数据,如果请求头为application/json(json格式),multipart/form-data(文件)等格式无法取到,只有在request.body里面能取到原生的数据。当发送过来的是JSON数据是,request.POST取到的数据是空的,这时只有用request.body取,再反序列化才能使用。
    # 增def post(self, request):# 获取提交json格式的数据post_data = json.loads(request.body)# 将数据写入到表中, 写入成功放回创建的数据对象# book_obj = models.Book.objects.create(**post_data)  # Book object 数据对象book_obj = models.Book.objects.filter(pk=1).first()# 组织返回的数据格式:back_dic = {'code': 201,'msg': '操作成功',}back_dic['book_obj'] = book_obj.get_data()print(back_dic)return JsonResponse(back_dic)

10.3 查

请求方式get
127.0.0.1:8000/api/books/v1/ 获取所有的数据 数据为一个列表套字典, js的元组套对象.
定义一个函数去处理路由的数据, 获取路由中的主键
# 定义一个函数获取路由中的主键值
def get_id(request):path = request.path  # /api/books/v1/path_list = path.split('/')# ['', 'api', 'books', 'v1', ''] 去除空 ['api', 'books', 'v1']for i in path_list:if not i:path_list.remove(i)# 解压赋值拿到最后一个值*_path, book_id = path_listreturn book_id
# 写数图类, 继承View
class Book(View):# 定义五个方法 get, post, put, patch, delete# 查def get(self, request):# 获取get请求数据book_id = get_id(request)# 返回值back_dic = {'code': 200,'msg': '查询成功',}# 如果是book_id是纯数数字则作为主键取值, 不是则取所有的数据if book_id.isdigit():book_obj = models.Book.objects.filter(pk=book_id).first()back_dic['book_obj'] = book_obj.get_data()# 获取所有数据else:book_obj = models.Book.objects.all()book_obj_list = []for obj in book_obj:print(obj)book_obj_list.append(obj.get_data())back_dic['book_obj'] = book_obj_listprint(back_dic)return JsonResponse(back_dic)

10.3 改

提交put请求, 创建成功之后返回单个数据对象 修改数据以路由中的之间为主
提交地址: 127.0.0.1:8000/api/books/v1/1/
提交数据格式json: (id不需要提交, json格式数据是双引号)
    # 增def post(self, request):# 获取提交json格式的数据post_data = json.loads(request.body)# 将数据写入到表中, 写入成功放回创建的数据对象# book_obj = models.Book.objects.create(**post_data)  # Book object 数据对象book_obj = models.Book.objects.filter(pk=1).first()# 组织返回的数据格式:back_dic = {'code': 201,'msg': '操作成功',}back_dic['book_obj'] = book_obj.get_data()print(back_dic)return JsonResponse(back_dic)# 局部修改def put(self, request):# 主键需要以地址为准book_id = get_id(request)if book_id.isdigit():# 反序列化put_data = json.loads(request.body)# 修改数据models.Book.objects.filter(pk=book_id).update(**put_data)# 查book_obj = models.Book.objects.filter(pk=book_id).first()# 返回值back_dic = {'code': 200,'msg': '查询成功',}back_dic['book_obj'] = book_obj.get_data()else:back_dic = {'code': 404,'msg': '路径不存在',}return JsonResponse(back_dic)

10.5 删

提交delete请求, 删除成功之后返回空, 删除数据以路由中的之间为主
提交地址: 127.0.0.1:8000/api/books/v1/1/
提交数据格式json: (id不需要提交, json格式数据是双引号)
    # 删除def delete(self, request):book_id = get_id(request)if book_id.isdigit():# 删除数据num = models.Book.objects.filter(pk=book_id).delete()# 返回数据print(num)  # (0, {'app01.Book': 0})if num[0]:back_dic = ''return HttpResponse(back_dic)back_dic = {'code': 404,'msg': '路径不存在!'}return JsonResponse(back_dic)

0. DRF之软件开发模式CBV源码解析相关推荐

  1. MyBatis源码- SqlSession门面模式 selectList 源码解析

    文章目录 Pre 工程概览 pom.xml mybatis-config.xml UserMapper 测试类 selectList 源码解析 附 SQL log4j.properties app.p ...

  2. Python数据爬取之0基础小白实战(三)源码解析

    前两篇(一)软件安装.(二)初窥门槛我解决了软件版本不匹配的问题并学习关键技术.找到重要源码,完成了程序思路总体设计,本篇废话不多说,我们直接上源码. 任务描述 获取2015-2020年通过申请的国家 ...

  3. 【Android应用开发】EasyDialog 源码解析

    示例源码下载 : http://download.csdn.net/detail/han1202012/9115227 EasyDialog 简介 : -- 作用 : 用于在界面进行一些介绍, 说明; ...

  4. nginx开发笔记_ngx_hash源码解析

    ngx_hash源码解析 ngx_hash是nginx中的hash表结构,具有以下特点: 静态结构,hash表创建后无法动态添加/删除KV. 采用连续存储方式解决碰撞问题.即出现碰撞的KV存放在连续地 ...

  5. 外盘期货配资软件开发,全套源码C#+mysql

    外盘期货配资软件开发,期货资管软件定制,信管家高仿,全套源码,C#+mysql:功能介绍:手动和自动相结合,客户大数据实时分析,通过系统各项参数,进行人工智能决策,实现敞口.持仓实时监控风险自动计算, ...

  6. 软件开发为什么需要源码

    源代码(也称源程序)是指未编译的按照一定的程序设计语言规范书写的文本文件,是一系列人类可读的计算机语言指令. 在现代程序语言中,源代码可以是以书籍或者磁带的形式出现,但最为常用的格式是文本文件,这种典 ...

  7. Kubernetes CRD开发模式及源码实现深入剖析-Kubernetes商业环境实战

    专注于大数据及容器云核心技术解密,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客.如有任何学术交流,可随时联系.留言请关注<数据云技术社区>公众号. 1 CRD资源扩展 CRD ...

  8. 未能加载文件或程序集rsy3_abp vnext2.0之核心组件模块加载系统源码解析

    abp vnext是abp官方在abp的基础之上构建的微服务架构,说实话,看完核心组件源码的时候,很兴奋,整个框架将组件化的细想运用的很好,真的超级解耦.老版整个框架依赖Castle的问题,vnext ...

  9. abp vnext2.0之核心组件模块加载系统源码解析

    abp vnext是abp官方在abp的基础之上构建的微服务架构,说实话,看完核心组件源码的时候,很兴奋,整个框架将组件化的细想运用的很好,真的超级解耦.老版整个框架依赖Castle的问题,vnext ...

最新文章

  1. linux文件权限详解
  2. 给eth0增加一个IP
  3. aliyun maven 添加jar_阿里云Maven配置,Maven仓库配置,Maven镜像配置
  4. python模型_python 模型的释义
  5. mysql dcn_Mysql varchar(max)
  6. python双线性插值函数_双线性插值法原理 python实现
  7. Java 随心笔记7
  8. fastReport 绑定DataBand数据源后还是打印出一条数据
  9. 关于配置了数据库方言为MySQLInnoDBDialect后Hibernate不能自动建表的问题
  10. VMware workstations pro16.23已经安装vmware tool,Ubuntu仍然无法复制粘贴
  11. Android手机投屏利器米卓同屏助手
  12. DSPF28335学习笔记之(1)CMD文件说明
  13. 搞着玩:基于Spring Boot的企业CMS系统
  14. Android中Intent的介绍
  15. windows7蓝牙怎么打开_避开网络限制,通过蓝牙共享网络连接
  16. [悦读] 让听得见炮声的人来决策——《赋能》读书笔记
  17. Ubuntu18.04美化主题(mac主题)
  18. 470计算机毕业设计
  19. LinuxIP白名单设置
  20. 防病毒软件测评权威机构

热门文章

  1. stata画时间趋势图时横坐标标签太长重叠怎么办
  2. java计算工作日_Java工作日计算工具类
  3. 微信公众号自定义菜单如何添加emoji表情图标?
  4. 【Golang】go语言实现数据结构——堆
  5. android电视 怎么调电视机的信号源,如何设置智能电视、盒子信号源?原来这么简单!具体方法如下...
  6. IOS 上传IPA到AppStore
  7. 一个屌丝程序猿的人生(七十九)
  8. 物联网卡技术的8种通信协议
  9. 【EasyRL学习笔记】第八章 针对连续动作的深度Q网络
  10. 【BZOJ 3470】3470: Freda’s Walk 期望