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的输入和输出.每个中间件组件都负责做一些特定的 ...
随机推荐
- C# DocumentCompleted事件多次条用解决方案
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { ...
- IAR添加debug和release选项
在IAR的Workspace窗口顶部的下拉菜单中有两个选项,Debug和Release. 名字和数量可以在菜单栏的Project-->Edit Configuration中增删修改 每个选项都对 ...
- 数组排序方法(join()、reverse()、sort())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- SVN安装与汉化
官网地址:http://tortoisesvn.net/downloads.html 如地址过期可自行百度官网,下载安装包安装64/32位 如果需要汉化的同学,同样在下载页面,往下拉Language ...
- 题解 [APIO2014]连珠线
题解 [APIO2014]连珠线 题面 解析 首先这连成的是一棵树啊. 并且\(yy\)一下,如果钦定一个根, 那么这上面的蓝线都是爸爸->儿子->孙子这样的,因为像下图这样的构造不出来: ...
- 冒泡排序之javascript
冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字 ...
- mouseout([[data],fn])
mouseout([[data],fn]) 概述 当鼠标指针从元素上移开时,发生 mouseout 事件. 该事件大多数时候会与 mouseover 事件一起使用.深圳dd马达 注释:与 mousel ...
- Codeforces 1175E Minimal Segment Cover
题意: 有\(n\)条线段,区间为\([l_i, r_i]\),每次询问\([x_i, y_i]\),问要被覆盖最少要用多少条线段. 思路: \(f[i][j]\)表示以\(i\)为左端点,用了\(2 ...
- mac charles 代理https
1.安装根证书:help - ssl proxying - install charles root certificate 2.这时候会弹出一个根证书界面,如果没有弹出,则可以去chrome,高级设 ...
- Ubuntu18.04安装和配置Django,并实现简单示例
一.前言(系统,django介绍,window.mac.linux简单区别) Django是python开发过程最重要的web框架.因为在看的Django教学视频是在mac下安装的,我自己用的是Lin ...