django 之(二) --- 源码分析
CBV类视图继承
CBV:继承自View;注册的时候使用的as_view()
入口
不能使用请求方法的名字作为参数的名字
只能接受已经存在的属性对应的参数
定义了一个view
创建了一个类视图对象
保留,拷贝传递进来的属性和参数
调用dispatch方法
分发
如果请求方法在我们的允许的列表中
从自己这个对象中获取请求方法名字小写对应的属性,如果没有找到,会给一个默认http_method_not_allowded
如果请求方法不在我们允许的列表中,直接就是http_method_not_allowed
之后将参数传递,调用函数
默认实现了options
获取接口信息,可以获取接口都允许什么请求
- 类视图继承自View;注册时使用as_view()
from django.conf.urls import url
from CBV import views urlpatterns = [
url(r'^hello/', views.HelloCBV.as_view(msg='Sleeping'), name='hello'),
url(r'^books/', views.BooksCBV.as_view(), name='books'),
]
- as_view 源码(base.py文件中)
- 流程:as_view --> dispatch分发 --> 调用实现请求方法对应的函数名
class View(object):
"""
Intentionally simple parent class for all views. Only implements
dispatch-by-method and simple sanity checking.
"""
# 允许的请求方法
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in six.iteritems(kwargs):
setattr(self, key, value) @classonlymethod
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))
# 定义了一个view
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get # 默认get请求和head请求方式一样;支持get就支持head请求
self.request = request # 将请求的参数,属性记录下来(三行)
self.args = args
self.kwargs = kwargs
# 返回时调用dispatch方法
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 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.
# 将请求方法名变为小写,并判断请求方法名是否在允许的请求列表中
if request.method.lower() in self.http_method_names:
# 如果在允许的请求列表中,从自己的对象中去获取请求方法名字小写的属性,没有找到给变量一个默认值
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else: # 如果请求方法不在被允许的请求列表中,则http_method_not_allowd给变量
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning(
'Method Not Allowed (%s): %s', request.method, request.path,
extra={'status_code': 405, 'request': request}
)
return http.HttpResponseNotAllowed(self._allowed_methods())
# 获取接口信息,获取接口都允许接收什么请求
def options(self, request, *args, **kwargs):
"""
Handles responding to requests for the OPTIONS HTTP verb.
"""
response = http.HttpResponse()
response['Allow'] = ', '.join(self._allowed_methods())
response['Content-Length'] = ''
return response def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
类视图子类
[这些子类和模版是高度耦合的,在前后端分离中不会被使用。Mixin:只要继承中有此单词,就表示混合多继承]
TemplateView是多继承的子类,继承自:
- View:分发函数:dispatch
- ContextMixin:接收上下文(从视图函数传递到模板的内容)。函数:get_context_data
- TemplateResponseMixin:将内容渲染到模板中。属性:template_name、template_engine、response_class、content_type。函数:render_to_response
base.py 源码分析
# TemplateView
class TemplateView(TemplateResponseMixin, ContextMixin, View):
"""
A view that renders a template. This view will also pass into the context
any keyword arguments passed by the URLconf.
"""
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
views.py 使用
from django.views.generic import TemplateView # CBV继承TemplateView,实现了get请求,继承自:TemplateResponseMixin, ContextMixin, View(实现请求分发)
class HelloTemplateView(TemplateView):
template_name = 'hello.html'
ListView是多继承子类。继承自:
MultipleObjectTemplateResponseMixin
TemplateResponseMixin
获取模板名字,首先根据template_name获取;如果没找到,自己根据应用的名字,关联模型的名字,_list.html 去查找,App/book_list.html
BaseListView
MultipleObjectMixin
ContextMixin、get_queryset、model
View:默认实现了get,渲染成了response
views.py 使用
from django.views.generic import ListView
from App.models import Book # CBV继承ListView,实现了get请求。获取一个集合数据
# ListView继承自:MultipleObjectTemplateResponseMixin, BaseListView
class HelloListView(ListView):
template_name = 'BookList.html'
model = Book
book.html
<body>
<ul>
{% for book in object_list %}
<li><a href="{% url 'cbv:single' pk=book.id %}">{{ book.b_name }}</a></li>
{% endfor %}
</ul>
</body>
DetailView是多继承子类。继承自:
- SingleObjectTemplateResponseMixin
- TemplateResponseMixin:重写了获取模板名字的方法
- BaseDetailView
- View、SingleObjectMixin
views.py 使用
from django.views.generic import DetailView
from App.models import Book # CBV继承DetailView。继承自SingleObjectTemplateResponseMixin, BaseDetailView
class HeDetailView(DetailView):
# template_name = 'Book.html' #. 如果不指定模版,自动去查找名字为:book_detail.html的模版
# model = Book
queryset = Book.objects.all()
urls.py
from django.conf.urls import url
from App import views urlpatterns = [ # 单一实例:pk、slug
url(r'^single/(?P<pk>\d+)/', views.HeDetailView.as_view(), name='single'),
]
APIView源码分析
APIView源码封装的类及用途
- renderer_classes: 渲染的类
- parser_classes: 解析转换的类
- authentication_classes: 认证的类
- throttle_classes: 节流的类、控制请求频率的[此接口每分钟请求多少次]
- permission_classes: 权限的类
- content_negotiation_class:内容过滤类
- metadata_class: 元信息的类
- versioning_class: 版本控制的类
- as_view( )方法:调用父类中的as_view。对dispatch重写,主要做dispatch分发。
- 重写的dispatch方法中的 initialize_request 方法初始化一个新的request。
- 使用django的request构建了一个REST中的Request,
- 将Django中的Request作为了自己的一个私有属性 _request
- (若在rest_formwork中获取django的request,需要request._reuqest)
- initial 初始化。获取接受的渲染、获取接受的类型、版本是否支持
- perform_authentication:
- 执行用户认证。request.user[.user中将方法改为属性,并进行认证]
- 遍历用户认证器,如果认证成功会返回一个元组
- 元组中的第一个元素就是 user
- 第二个元素就是 auth [token]
- 执行用户认证。request.user[.user中将方法改为属性,并进行认证]
- check_permissions
- 检查用户权限
- 遍历权限检测器
- 只要有一个权限检测没通过就直接显示权限被拒绝
- 只有所有权限都满足,才算是拥有权限
- 检查用户权限
- check_throttles
- 检测访问频率
- 遍历频率限制器
- 如果验证不通过,就需要等待
- 检测访问频率
- perform_authentication:
- initial 初始化。获取接受的渲染、获取接受的类型、版本是否支持
- csrf_exempt
- 所有APIView的子类都是csrf豁免的
Request源码分析
Request
它是rest_framework的request。(rest_framework.request)
将Django中的Request作为了自己的一个属性 _request
属性和方法
content_type: 传输内容的类型
stream: 流
query_params:查询参数。[可以在post请求中获取GET参数][将Django中的request.GET方法改名为query_params]
data: 处理任意数据,同时兼容 POST,PUT,PATCH
user: 可以直接在请求上获取用户。[相当于在请求上添加一个用户对象属性]
auth: 认证。相当于请求上添加了一个属性,属性值是token
successful_authenticator:认证成功
Response源码分析
Response
依然是HttpResponse的子类。只要类视图继承自APIView后,
Response自己封装的data 直接接受字典转换成JSON [ Response(data=request.data, status(状态码)=201) ]
属性和方法
rendered_content:渲染的内容
status_text:状态码转成常量
封装 status模块中,实际上就是一个常量类
针对视图函数的包装
REST框架提供了两种可用于编写API视图的包装器(wrappers)
- CBV:APIView
- FBV:添加 @api_view装饰器;必须手动指定允许的请求方法
- @api_view(http_method_names=['GET', 'POST'])
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from RestSerializers.serializers import BookSerializer @api_view(http_method_names=['GET', 'POST'])
def books(request):
print(type(request))
if request.method == "GET":
return Response(data={"msg": "get ok"})
elif request.method == "POST":
print(request.data)
book_serializer = BookSerializer(data=request.data)
if book_serializer.is_valid():
book_serializer.save()
return Response(data=book_serializer.data)
return Response(data={'msg': 'error'}, status=status.HTTP_400_BAD_REQUEST)
APIView类视图子类
GenericAPIView继承自APIView;GenericAPIView是一个基类
generics包中。子类:
GenericAPIView
增加的模型的获取操作
get_queryset:获取查询结果集
get_object: 获取单个对象。lookup_field 默认pk
get_serializer:序列化实例
get_serializer_class: 获取序列化类
get_serializer_context: 获取序列化上下文内容
filter_queryset: 对查询结果集过滤
paginator: 直接构件的分页器
paginate_queryset: 对查询结果集分页
get_paginated_response:获取分页后的结果
CreateAPIView
创建的类视图。实现了post进行创建
继承自GenericAPIView
继承自CreateModelMixin
ListAPIView
列表的类视图。实现了get
继承自GenericAPIView
继承自ListModelMixin
RetrieveAPIView
查询单个数据的类视图。实现了get
继承自GenericAPIView
继承自RetrieveModelMixin
DestroyAPIView
销毁数据的类视图,删除数据的类视图。实现了delete
继承自GenericAPIView
继承自DestroyModelMixin
UpdateAPIView
更新数据的类视图。实现了put、patch
继承自GenericAPIView
继承自UpdateModelMixin
ListCreateAPIView
获取列表数据,创建数据的类视图。实现了get、post
继承自GenericAPIView
继承自ListModelMixin
继承自CreateModelMixin
RetrieveUpdateAPIView
获取单个数据,更新单个数据的类视图。实现了get、put、patch
继承自GenericAPIView
继承自RetrieveModelMixin
继承自UpdateModelMixin
RetrieveDestroyAPIView
获取单个数据,删除单个数据。实现了get、delete
继承自GenericAPIView
继承自RetrieveModelMixin
继承自DestroyModelMixin
RetrieveUpdateDestroyAPIView
获取单个数据,更新单个数据,删除单个数据的类视图。实现了get、put、patch、delete
继承自GenericAPIView
继承自RetrieveModelMixin
继承自UpdateModelMixin
继承自DestroyModelMixin
mixins
CreateModelMixin
create
perform_create
get_success_headers
ListModelMixin
list:查询结果集,添加分页,帮你序列化
RetrieveModelMixin
retrieve:获取单个对象并进行序列化
DestroyModelMixin
destroy:
获取单个对象
调用执行删除
返回Respon 状态码204
perform_destroy
默认是模型的delete
如果说数据的逻辑删除。重写进行保存
UpdateModelMixin
update:获取对象,合法验证;执行更新
perform_update
partial_update:差量更新,对应的就是patch
viewsets继承自:
ViewSetMixin:
重写as_view。添加过滤和反向解析
GenericViewSet
继承自GenericAPIView
继承自ViewSetMixin
ViewSet
继承自APIView
继承自ViewSetMixin
默认啥都不支持,需要自己手动实现
ReadOnlyModelViewSet
只读的模型的视图集合
继承自RetrieveModelMixin
继承自ListModelMixin
继承自GenericViewSet
ModelViewSet
直接封装对象的所有操作
继承自GenericViewSet
继承自CreateModelMixin
继承自RetrieveModelMixin
继承自UpdateModelMixin
继承自DestroyModelMixin
继承自ListModelMixin
封装使用1:
- user/serializers.py
from rest_framework import serializers
from user.models import User
# ModelSerializer没有超链接的序列化
class SingleUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password', 'phone',]
- user/models.py
from django.db import models class User(models.Model):
username = models.CharField(max_length=20, unique=True)
password = models.CharField(max_length=128)
phone = models.CharField(max_length=11)
add_time = models.DateTimeField(auto_now=True) class Meta:
db_table = 'user' def __str__(self):
return self.username
- user/views.py
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from user.models import User
from user.serializers import SingleUserSerializer class UserResouce(ListCreateAPIView):
# 操作的模型
queryset = User.objects.all()
# 此模型对应的序列化类
serializer_class = SingleUserSerializer class UserResourcePro(RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = SingleUserSerializer
- user/urls.py
from django.urls import path
from user.views import UserResouce, UserResourcePro app_name = 'user'
urlpatterns = [
path('single', UserResouce.as_view(), name='single'),
path('singlepro/<int:pk>', UserResourcePro.as_view(), name='singlepro'),
]
终极封装:
- user/views.py
from rest_framework.viewsets import ModelViewSet
from user.models import User
from user.serializers import SingleUserSerializer class UserResourceVPro(ModelViewSet):
queryset = User.objects.all()
serializer_class = SingleUserSerializer
- user/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from user.views import UserResourceVPro router = DefaultRouter()
router.register(r'single', UserResourceVPro)
# 此方式也可以获取单个对象:http://127.0.0.1:8000/user/single/2/
# 主路由中
8 urlpatterns = [
path('', include(router.urls))
]
封装使用2:
- urls.py
from django.conf.urls import url, include
from django.contrib import admin
from App.urls import router urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app/', include('App.urls')),
url(r'^app/', include(router.urls)),
]
- App/urls.py
from django.conf.urls import url
from rest_framework.routers import DefaultRouter
from App import views
from App.views import GameModelViewSet urlpatterns = [
url(r'^games/$', views.GamesView.as_view()),
url(r'^games/(?P<pk>\d+)/$', views.GameView.as_view(), name='game-detail'),
] 11 router = DefaultRouter()
12 router.register(r'progames', GameModelViewSet)
- App/models.py
from django.db import models class Game(models.Model):
g_name = models.CharField(max_length=32)
g_price = models.FloatField(default=0)
- App/serializers.py
from rest_framework import serializers
from App.models import Game
# HyperlinkedModelSerializer带超链接的序列化
class GameSerializer(serializers.HyperlinkedModelSerializer): class Meta:
model = Game
fields = ('url', 'id', 'g_name', 'g_price')
- App/views.py
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.viewsets import ModelViewSet
from App.models import Game
from App.serializers import GameSerializer class GamesView(ListCreateAPIView):
serializer_class = GameSerializer
queryset = Game.objects.all() class GameView(RetrieveUpdateDestroyAPIView):
serializer_class = GameSerializer
queryset = Game.objects.all() class GameModelViewSet(ModelViewSet):
serializer_class = GameSerializer
queryset = Game.objects.all()
django 之(二) --- 源码分析的更多相关文章
- Django之DRF源码分析(二)---数据校验部分
Django之DRF源码分析(二)---数据校验部分 is_valid() 源码 def is_valid(self, raise_exception=False): assert not hasat ...
- Django搭建及源码分析(三)---+uWSGI+nginx
每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...
- Django如何启动源码分析
Django如何启动源码分析 启动 我们启动Django是通过python manage.py runsever的命令 解决 这句话就是执行manage.py文件,并在命令行发送一个runsever字 ...
- Django rest framework源码分析(1)----认证
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Django rest framework源码分析(一) 认证
一.基础 最近正好有机会去写一些可视化的东西,就想着前后端分离,想使用django rest framework写一些,顺便复习一下django rest framework的知识,只是顺便哦,好吧. ...
- Django rest framework源码分析(3)----节流
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Django rest framework 源码分析 (1)----认证
一.基础 django 2.0官方文档 https://docs.djangoproject.com/en/2.0/ 安装 pip3 install djangorestframework 假如我们想 ...
- django CBV视图源码分析
典型FBV视图例子 url路由系统 from django.conf.urls import url from django.contrib import admin from luffycity.v ...
- Django中间件部分源码分析
中间件源码分析 中间件简介 中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于在全局范围内改变Django的输入和输出.每个中间件组件都负责做一些特定的 ...
随机推荐
- JAVA遇见HTML——Servlet篇:应用MVC架构实现项目
java关键字“this”只能用在方法方法体内.当一个对象创建之后,java虚拟机就会给这个对象分配一个引用自身的指针,这个指针的名字就是this.只能在非静态方法中使用 package servle ...
- CallContext线程数据缓存-调用上下文
一.CallContext 概述 命名空间:System.Runtime.Remoting.Messaging CallContext 用于提供与执行代码路径一起传送的属性集,直白讲就是:提供线程(多 ...
- 四十九. Zabbix报警机制 、 Zabbix进阶操作 、 监控案例
案例1:实现Zabbix报警功能 案例2:Zabbix自动发现 案例3:Zabbix主动监控 案例4:拓扑图与聚合图形 案例5:自定义监控案例 1 案例1:实现Zabbix报警功能 1.1 问题 沿用 ...
- bzoj2725
* 给出一张图 * 每次删掉一条边后求 the shortest path from S to T * 线段树维护最短路径树 * 具体维护从某点开始偏离最短路而到达 T 的最小距离 * 首先记录下最短 ...
- 在windows10 Linux (centos7)中安装go golang (够浪) 并测试运行
官方下载安装页面 https://golang.org/doc/install git主页 https://github.com/golang/go 相关下载地址 https://golang.org ...
- Echarts-复杂关系图(源码)
关系图: 代码: <!DOCTYPE html> <head> <meta charset="utf-8"> <script type=& ...
- JavaWeb_(Mybatis框架)动态sql_七
系列博文: JavaWeb_(Mybatis框架)JDBC操作数据库和Mybatis框架操作数据库区别_一 传送门 JavaWeb_(Mybatis框架)使用Mybatis对表进行增.删.改.查操作_ ...
- oracle行转列和列转行(pivot 和 unpivot 函数,wm_concat函数 )
create table demo(id int,name varchar(20),nums int); ---- 创建表insert into demo values(1, '苹果', 1000); ...
- Java并发指南6:Java内存模型JMM总结
本文转载自互联网,侵删 在前面的文章中我们介绍了Java并发基础和线程安全的概念,以及JMM内存模型的介绍,包括其定义的各种规则.同时我们也介绍了volatile在JMM中的实现原理,以及Lock ...
- HTTP之持久连接
HTTP/1.1 允许 HTTP 设备在事务处理结束之后将 TCP 连接保持在打开状态,以便为未来的 HTTP 请求重用现存的连接.在事务处理结束后仍然保持在打开状态的 TCP 连接被称为持久连接.非 ...