django的请求生命周期

{drf,resful,apiview,序列化组件,视图组件,认证组件,权限组件,频率组件,解析器,分页器,响应器,URL控制器,版本控制}

一、CBV源码分析
准备工作:
新建一个Django项目
写一个基于类的视图


继承,写get,post方法

from django.shortcuts import render, HttpResponse

from django.views import View
from django.http import JsonResponse # Create your views here. class Test(View): def dispatch(self, request, *args, **kwargs):
# codes
obj = super().dispatch(self, request, *args, **kwargs)
# codes
return obj def get(self, request, *args, **kwargs):
return HttpResponse('cbv_get') def post(self, request, *args, **kwargs):
return HttpResponse('cbv_post')

视图写好之后写路由
把views导过来,

类名.as_view()  直接执行

from django.conf.urls import url
from django.contrib import admin
from appp01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
# 在这里写的 views.Test.as_view(),实际上就是as_view()里面view的内存地址
url(r'^test/', views.Test.as_view()), ]

分析一下执行的流程:
  如果当初放的是函数内存地址不会去执行,请求来了经过路由做分发。但是如果放的是函数加括号直接就执行了(程序一点一运行立马这里就执行),执行Test.as_view的方法,

  Test里面没有as_view,所以执行的是父类View里面的as_view方法

打开父类的View找到as_view方法,类来调用就把类传入,定义了一个view函数,最后返回了这个view,所以在路由层写的实际上就是view(as_view()内部的)这个函数的内存地址。

当请求来了,来了执行的实际上就是view加括号执行。在执行前

这里面外层函数有个cls(这个cls就是Test这个类,产生了对象赋值给了self。),在内部函数有个对外部作用域的引用,所以这个view就是一个闭包函数。

把请求的request对象赋到了self.request里面

最后返回了一个self.dispatch函数,其实就是在执行这个函数。

这个dispatch函数就是生成的Test这个类的,这个Test类里面没有这个dispatch,所以执行的是View的dispatch。

所以请求来了就是执行dispatch方法

这里面取到请求的小写,判断在不在self.http_method_names中,如果是get请求在这个列表里面

通过getattr反射,self是Test对象,找到get方法,找不到返回错误提示(

self.http_method_not_allowed

handler=test对象中get方法的内存地址,

两层判断。

看self.http_method_names源码

self.http_method_not_allowed源码

源码执行的流程?
CBV源码分析
cbv和fbv
1 在views中写一个类,继承View,里面写get方法,post方法
2 在路由中配置: url(r'^test/', views.Test.as_view()),实际上第二个参数位置,放的还是一个函数内存地址
3 当请求来了,就会执行第二个参数(request,参数),本质上执行view()
4 view内部调用了dispatch()方法
5 dispatch分发方法,根据请求方式不同,执行的方法不同

二、resful规范  ----->软件开发的一种规范,好处是方便前台跟后台交互,后台跟后台交互可以直接访问
面向资源架构,面向资源编程。把网络上所有东西都当成资源。

10个规范
1.与后台做交互,通常采用https协议,这样安全

2.域名 有两种格式
https://api.baidu.com 这就说明这是百度提供的这个接口,这种存在跨域问题。
https://www.baidu.com.api/

3.版本 ,接口不能保证不改动
https://www.baidu.com.api/v1
https://www.baidu.com.api/v2

4.路径上所有的东西都是资源,均使用名词来表示。不用动词get,delet。。。
https://www.library.com.api/v1/books/ 拿所有书
https://www.library.com.api/v1/book/ 拿一本书

5.method(请求的方式)来表示增删查改,链接上看不出来只有在请求方式上能看出来增删查改。
https://www.library.com.api/v1/books/ get请求,获取所有书
https://www.library.com.api/v1/books/ post请求,新增一本书
https://www.library.com.api/v1/book/1 delete请求,删除一本id为1的书
https://www.library.com.api/v1/book/1 get请求,获取id为1的这本书
https://www.library.com.api/v1/book/1 put/patch请求,修改id为1的这本书

6.过滤条件
https://www.library.com.api/v1/books?limit=10 只拿前十本书
https://www.library.com.api/v1/books?price=20 只拿价格为20元的书

7.状态码
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
等价于:{'status':100,}

8.错误处理,返回错误信息,error当做key
{status:101,error:"不可以这样"}

9.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

10.返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
返回结果中提供链接(获取一本书)
{
id:1
name:xxx
price:12
publish:www.xxx.com.api/v1/publish/1

}

三、Django中写resful的接口
路由设计很重要。

urlpatterns = [
url(r'^users/', views.users),
url(r'^user/(?P<id>\d+)', views.user),
]

模拟数据库,列表嵌套字典

users_list = [{"id":1,"name":'zrg',"age":18},{"id":2,"name":'yj',"age":19},{"id":3,"name":'xyw',"age":18}]

def users(request):
# 返回字典里面写status,如果成功的话。 需要把users_list取到的数据赋给response
response = {'status': 100, 'erros': None}
# 如果method等于get请求的话获取所有用户,并且返回resful规范
if request.method == 'GET':
response['users'] = users_list
# 导入JsonResponse,字典里面套了列表所以safe=False
return JsonResponse(response, safe=False)
# 如果method等于post请求,新增
if request.method == 'POST':
# 新增的话,数据取出来添加到users_list里面去
name = request.POST.get('name')
age = request.POST.get('age')
users_list.append({'id': len(users_list) + 1, 'name': name, 'age': age})
# response['user']={'name':name,'age':age}
response['msg'] = '新增成功'
return JsonResponse(response)

# 单个的增删改
# 把参数传过来,通过分组来做(有名无名分组)

# 单个的增删改
# 把参数传过来,通过分组来做(有名无名分组)
def user(request, id):
response = {'status': 100, 'erros': None}
if request.method == 'GET':
id = int(id)
response['user'] = users_list[id]
return JsonResponse(response)

用postman提交不会自动补/,在浏览器会自动补/(中间件的原理添加)。

所以在postman这个软件里用就写全的路径!get请求可以重定向,post请求没有重定向这一说。

四、drf写resful的接口   是一个app
drf:Djangorestframework
1.安装

pip3 install Djangorestframework

在pycharm里也可以安装

2.简单使用

要使用先去APP里注册

基于drf写接口,写cbv,视图层# 基于drf写接口,写cbv
# 没有也可以写,有了更好写接口
# 导入rest_framework里面的views
from rest_framework.views import APIView
from rest_framework.response import Response # Response 也是继承了HttpResponse,这个Response就传一个字典就可以了,会自动序列化。 # 写类继承APIView,写get,post方法
# class DrfTest(views.APIView):
# 等同于
class DrfTest(APIView):
def get(self, request, *args, **kwargs):
response = {'status': 100, 'erros': None}
response['users'] = users_list
# 传列表传字典
# 用drf的Response,可以通过请求客户端来判断返回数据格式是什么样的,用浏览器返回的是页面。。。
return Response(response) # 返回JsonResponse也可以,有数据,没页面 def post(self, request, *args, **kwargs):
name = request.data.get('name')
pass
# 原生Django只能处理form-data 和 urlencode 编码,json处理不了,drf就能处理了,但是取值从大写POST里面取值。
    def post(self, request, *args, **kwargs):
# 传参
# data方法这里面是所有编码方式都能转成字典
name = request.data.get('name') #从data这个字典里拿到post提交的form-data 和 urlencode ,json格式的数据
print(name)
return HttpResponse('ok')

APIVIew源码分析
dispatch方法:
# 传入的request是原生的request对象
# 这个request已经不是原生的request了,但是它内部有个原生的request对象

request = self.initialize_request(request, *args, **kwargs)
self.initial(request, *args, **kwargs)#这里面有权限,认证,频率

Request源码的分析

as_view,dispatch,self.initialize_request,里面Request

request.data实际上是个方法,才转换数据(如果前端传的formdata,URLencode就从大写post返回,如果json从body体里拿出来转换回来。---->解析器)

也有request.method,触发attr,反射原来的request

request.POST,等价于request._request.POST

request.GET

Request源码分析
request.data其实是个方法,被包装成了属性
重写了__getattr__

print(request.GET)
# 就相当于:
print(request.query_params)   query_params----->查询的参数

五、drf之序列化组件

  序列化:把Python中的对象转成json格式字符串

  反序列化:把json格式转换成我樱桃红对象

序列化组件

Serializer

ModelSerialier

class MEta:

  model

  fields

  depth

  publish=

全局,局部钩子函数

反序列化:

  保存

  修改

全局跟局部钩子 看源码底往上走,自己-父类-父类的父类。。。。 self当前序列化的对象

----------------- ------------------- ------------------- -------------

第二步 使用 books_xlh = BookXlh(books_l,many=True)

books_xlh.data就是序列化完成的字典
from django.shortcuts import render

# Create your views here.
from rest_framework.response import Response from rest_framework.views import APIView from app01 import models from app01.Myxlh import BookXlh # # 写一个获取所有图书的接口
# class Books(APIView):
# def get(self,request,*args,**kwargs):
# # 所有图书拿出来,转成json格式
# books_l=models.Book.objects.all()
# # 用的话,要序列化谁,就写一个序列化类(新建文件夹或py文件),这个类继承一个东西,
# # 然后用的时候直接用这个类生成一个对象就可以了。
# # 比如序列化这个book,就单独为这个book写个序列化的类
#
# # 用BookXlh需要导入
# # 第一个参数需要序列化的queryset对象,第二个参数many=True(如果序列化多条必须)
# books_xlh = BookXlh(books_l,many=True)
# # isinstance=单个对象的时候,many=False 比如 books_l=models.Book.objects.all().first
# print(books_xlh.data) #是一个字典
# return Response(books_xlh.data) # 优化以上代码
# 写一个获取所有图书的接口
class Books(APIView): def get(self, request, *args, **kwargs):
# 字典应该是:
response = {'status': 100, 'msg': 'successful'}
# 所有图书拿出来,转成json格式
books_l = models.Book.objects.all()
# 用的话,要序列化谁,就写一个序列化类(新建文件夹或py文件),这个类继承一个东西,
# 然后用的时候直接用这个类生成一个对象就可以了。
# 比如序列化这个book,就单独为这个book写个序列化的类 # 用BookXlh需要导入
# 第一个参数需要序列化的queryset对象,第二个参数many=True(如果序列化多条必须)
books_xlh = BookXlh(books_l, many=True)
# isinstance=单个对象的时候,many=False 比如 books_l=models.Book.objects.all().first
print(books_xlh.data) # 是一个字典
response['books'] = books_xlh.data
return Response(response) # 获取一本书的
class Book(APIView):
def get(self, request, id):
response = {'status': 100, 'msg': '成功了'}
book = models.Book.objects.filter(pk=id).first()
book_xlh = BookXlh(book, many=False)
response['book'] = book_xlh.data
return Response(response)

第一步先写一个类(要序列化哪个表模型,就对应着哪个表模型写一个序列化的类):class BookXlh(serializers.Serializer):

# 单独写类
from rest_framework import serializers
# from rest_framework.serializers import Serializer
from rest_framework.request import Request class BookXlh(serializers.Serializer):
# 写序列化哪个字段
id=serializers.CharField()
title=serializers.CharField()
price=serializers.CharField() # 用BookXlh需要导入
以上如果不指定source,字段名字必须跟数据库名字对应起来。

写路由
"""dj_cbv2 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^books/', views.Books.as_view()),
url(r'^book/(?P<id>\d+)', views.Book.as_view()),
]

source

一旦指定了source,字段名跟source的值一定不能重复。

# 单独写类
from rest_framework import serializers
# from rest_framework.serializers import Serializer
from rest_framework.request import Request class BookXlh(serializers.Serializer):
# 写序列化哪个字段
id=serializers.CharField()
# title=serializers.CharField()
# 尽量让名字不要跟数据库名字重合,通过source=可以改名。
name=serializers.CharField(source='title')
price=serializers.CharField() # 拿publish,拿到的是名字 publish_name = serializers.CharField(source='publish.name')
publish_id = serializers.CharField(source='publish.pk') # 把出版社所有东西都拿出来
publish_dic=serializers.SerializerMethodField() def get_publisn_dic(self,obj): #obj 就是当前book对象
return {'id':obj.publish.pk,'name':obj.publish.name} #这个字典赋给get_publisn_dic # 用BookXlh需要导入 # 注意:
#1、 变量名和source='xx',不能重合
#2、source还支持继续点
#3、source不仅支持字段还支持执行方法
#4、支持写方法,如下,方法一定要传一个参数,就是当前book对象
# # 把出版社所有东西都拿出来
# publish_dic = serializers.SerializerMethodField()
#
# def get_publisn_dic(self, obj): # obj 就是当前book对象
# return {'id': obj.publish.pk, 'name': obj.publish.name} # 这个字典赋给get_publisn_dic

序列化组件的源码 (source字段后放字段也行,放方法也可以)

publish_dic = serializers.SerializerMethodField() 
一定要有个方法跟他对应
def get_publisn_dic(self, obj):
这个方法的返回值就会赋给这个变量publish_dic
这个方法名字也是固定的就是get+字段名

获取作者

先写类并继承

class AuthorXlh(serializers.Serializer):
id=serializers.CharField()
name=serializers.CharField()
age=serializers.CharField()

在book类里,序列化得到。

    authors = serializers.SerializerMethodField()
def get_authors(self,obj):
# 所有作者requeryset对象
authors_list=obj.authors.all() author_xlh=AuthorXlh(instance = authors_list,many=True)
return author_xlh.data
# 列表推导式
# l1=['name':author.name,'id':author.pk for author in authors_list ]

继承ModelSerializer,这个是跟表模型绑定的序列化。

class BookXlh(serializers.ModelSerializer):

from app01 import models
class BookXlh(serializers.ModelSerializer):
# 固定写法
class Meta:
# 指定表模型
model= models.Book
# 要序列化所有字段
fields = '__all__'
# 只想序列化title 和 id 这两个字段
# fields = ['title','id']
# 如果想要publish字段显示出版社名字 # 不包含什么字段
# exclude=['title'] #不能和fields连用 不显示title字段 #联表的深度
depth=1 #深度是1 有关联的话往下查一层
# 缺点 全取出来,下几层的参数不可控制 # 全取出来之后,可以覆盖前面的值 ------>相当于重写某些字段
# 多写一个字段
publish = serializers.CharField(source='publish.name')
# 作者的详细信息
authors = serializers.SerializerMethodField()
def get_authors(self,obj):
# 拿到
authors_l=obj.authors.all()
# 序列化
author_xlh=AuthorXlh(instance=authors_l,many=True) return author_xlh.data

钩子函数

from app01 import models
class BookXlh(serializers.ModelSerializer):
# 固定写法
class Meta:
# 指定表模型
model= models.Book
# 要序列化所有字段
fields = '__all__'
# 只想序列化title 和 id 这两个字段
# fields = ['title','id']
# 如果想要publish字段显示出版社名字 # 不包含什么字段
# exclude=['title'] #不能和fields连用 不显示title字段 #联表的深度
# depth=1 #深度是1 有关联的话往下查一层
# 缺点 全取出来,下几层的参数不可控制 title = serializers.CharField(max_length=32, min_length=2, error_messages={'max_length': '太长了'}) # 局部跟全局钩子 # 这个参数是title条件过来的那个参数, def validate_title(self, value):
from rest_framework import exceptions
if value.startswith('sb'):
raise exceptions.ValidationError('不能以sb开头')
return value # 全取出来之后,可以覆盖前面的值 ------>相当于重写某些字段
# 多写一个字段
# publish = serializers.CharField(source='publish.name')
# # 作者的详细信息
# authors = serializers.SerializerMethodField()
# def get_authors(self,obj):
# # 拿到
# authors_l=obj.authors.all()
# # 序列化
# author_xlh=AuthorXlh(instance=authors_l,many=True)
#
# return author_xlh.data

增删查改的接口写法

   # 增加一本书,一般放在books里发请求上
# 新增怎么增?-----> 提交的字典,创建一个对象去保存(快速的方法,通过序列化组件保存----->必须继承自serializers.ModelSerializer),校验通过,默认不能为空
def post(self,request, *args, **kwargs):
response = {'status':100,'msg':'新增成功'}
book = request.data
book_xlh=BookXlh(data=book) #其实data=request.data # 什么数据都没写,默认不能为空 ,但是长度啊什么的没有限制
# 提交的子弹通过校验
if book_xlh.is_valid():
book_xlh.save()
response['book'] = book_xlh.data
else:
response['msg']=book_xlh.errors # return Response(book_xlh.data) return Response(response)

    # 删除,查出来直接delete
def delete(self,request,id):
response = {'status': 100, 'msg': '删除成功了'}
book = models.Book.objects.filter(pk=id).first().delete() return Response(response)

查就是获取

# 获取一本书的
class Book(APIView):
def get(self, request, id):
response = {'status': 100, 'msg': '成功了'}
book = models.Book.objects.filter(pk=id).first()
book_xlh = BookXlh(book, many=False)
response['book'] = book_xlh.data
return Response(response) # 修改书在book里面,put和putch请求都可以
def put(self,request,id):
response = {'status': 100, 'msg': '成功了'}
book = models.Book.objects.filter(pk=id).first()
book_xlh = BookXlh(data=request.data,instance=book) if book_xlh.is_valid():
book_xlh.save()
response['book'] = book_xlh.data
else:
response['msg']=book_xlh.errors return Response(response)

什么是跨域?

什么是幂等性?

最新文章

  1. Autofac - 事件
  2. TCP Socket 通讯(客户端与服务端)
  3. JS对Array进行自定制排序
  4. Java 中的 static 使用之静态初始化块
  5. ajax温习
  6. 20145207《Java程序设计》第7周学习总结
  7. Flash Air 打包安卓 ane
  8. 那么如何添加网站favicon.ico图标
  9. poj1149
  10. Hadoop MapReduce编程 API入门系列之mr编程快捷键活用技巧详解(四)
  11. 利用systemtap学习Linux路由代码
  12. HTTP请求错误400、401、402、403、404、405、406、407、412、414、500、501、502解析
  13. line-height:1.5和line-height:150%的区别
  14. WiFi-ESP8266入门http(2-1)文件系统-复杂结构的网页
  15. TensorFlow从入门到理解
  16. 通过DOS界面查看电脑上端口使用情况
  17. 多线程之共享变量.md
  18. Guitar Pro怎样可以快速打出三连音?
  19. WCF开发实战系列二:使用IIS发布WCF服务 转
  20. ORM框架(ITDOS实战源码)

热门文章

  1. C#深度学习の枚举类型(IEnumerator,IEnumerable)
  2. nginx配置tomcat负载均衡,nginx.conf配置文件的配置
  3. skip-thought vector 实现Sentence2vector
  4. python入门学习:5.字典
  5. 转://oracle deadlock死锁trace file分析之一
  6. MySQL笔记--注意
  7. Generative Adversarial Nets[EBGAN]
  8. DOM(一)
  9. Linux系统多网卡环境下的路由配置
  10. 初步学习Xamarin的感受