目录

版本

新建一个工程Myproject和一个app名为api

(1)api/models.py

from django.db import models

class UserInfo(models.Model):
USER_TYPE = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP')
) user_type = models.IntegerField(choices=USER_TYPE)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64)
group = models.ForeignKey('UserGroup',on_delete=models.CASCADE)
roles = models.ManyToManyField('Role') class UserToken(models.Model):
user = models.OneToOneField('UserInfo',on_delete=models.CASCADE)
token = models.CharField(max_length=64) class UserGroup(models.Model):
title = models.CharField(max_length=32) class Role(models.Model):
title = models.CharField(max_length=32)

(2)Myproject/urls.py

from django.contrib import admin
from django.urls import path,include urlpatterns = [
#path('admin/', admin.site.urls),
path('api/',include('api.urls') ),
]

(3)api/urls.py

# api/urls.py

from django.urls import path
from .views import UserView urlpatterns = [
path('users/', UserView.as_view()),
]

(4)views.py

# api/views.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.versioning import QueryParameterVersioning class UserView(APIView): versioning_class = QueryParameterVersioning def get(self,request,*args,**kwargs):
#获取版本
print(request.version)
return HttpResponse('用户列表')

(5)settings.py

#版本
REST_FRAMEWORK = {
"DEFAULT_VERSION":'v1', #默认的版本
"ALLOWED_VERSIONS":['v1','v2'], #允许的版本
"VERSION_PARAM":'version' #GET方式url中参数的名字 ?version=xxx
}

 1.url中通过GET传参

QueryParameterVersioning用于去GET参数中取version
http://127.0.0.1:8000/api/users/?version=v2

后台可以看到当前的版本

如果url中没有传版本参数,则显示默认的版本("DEFAULT_VERSION":'v1')

http://127.0.0.1:8000/api/users/

如果url传的版本超过settings中的允许范围则报错

http://127.0.0.1:8000/api/users/?version=v3

2.在URLPATH中获取

(1)修改api/urls.py

通常情况我门应该用URLPATH的方式,而不是用前面GET()传参方式

url里面通过正则表达式定义哪些版本,

# api/urls.py

from django.urls import path,re_path
from .views import UserView urlpatterns = [
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view()),
]

(2)views.py

URLPathVersioning:去url路径里面获取版本
# api/views.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.versioning import URLPathVersioning class UserView(APIView): versioning_class = URLPathVersioning def get(self,request,*args,**kwargs):
#获取版本
print(request.version)
return HttpResponse('用户列表')

这个URLPathVersioning我们可以放到settings里面,全局配置,就不用写到views里面,每个类都要写一遍了

settings.py

# 版本
# REST_FRAMEWORK = {
# "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
# "DEFAULT_VERSION":'v1', #默认的版本
# "ALLOWED_VERSIONS":['v1','v2'], #允许的版本
# "VERSION_PARAM":'version' #get方式url中参数的名字 ?version=xxx
# } #全局
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
}

修改views.py

# api/views.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request class UserView(APIView): def get(self,request,*args,**kwargs):
#获取版本
print(request.version)
return HttpResponse('用户列表')

浏览器访问地址

http://127.0.0.1:8000/api/v1/users/

然后后台拿到版本信息

3.反向解析访问的url

(1)api/urls.py

添加name = 'api_user'

# api/urls.py

from django.urls import path,re_path
from .views import UserView urlpatterns = [
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(),name = 'api_user'),
]

(2)views.py

# api/views.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request class UserView(APIView): def get(self,request,*args,**kwargs):
#获取版本
print(request.version)
#获取处理版本的对象
print(request.versioning_scheme)
#获取浏览器访问的url,reverse反向解析
#需要两个参数:viewname就是url中的别名,request=request是url中要传入的参数
#(?P<version>[v1|v2]+)/users/,这里本来需要传version的参数,但是version包含在request里面(源码里面可以看到),所有只需要request=request就可以
url_path = request.versioning_scheme.reverse(viewname='api_user',request=request)
print(url_path)
# self.dispatch
return HttpResponse('用户列表')

浏览器访问

http://127.0.0.1:8000/api/v1/users/

后台获取

源码流程

(1)dispatch

 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 handling.
"""
self.args = args
self.kwargs = kwargs
#对原始request进行加工,丰富了一些功能
#Request(
# request,
# parsers=self.get_parsers(),
# authenticators=self.get_authenticators(),
# negotiator=self.get_content_negotiator(),
# parser_context=parser_context
# )
#request(原始request,[BasicAuthentications对象,])
#获取原生request,request._request
#获取认证类的对象,request.authticators
#1.封装request
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate? try:
#2.认证
self.initial(request, *args, **kwargs) # Get the appropriate handler method
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 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

(2)initial

    def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
#request.version获取版本信息
#request.versioning_scheme获取处理版本你的对象
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
#4.实现认证
self.perform_authentication(request)
#5.权限判断
self.check_permissions(request)
#6.控制访问频率
self.check_throttles(request)

(3)determine_version

 def determine_version(self, request, *args, **kwargs):
"""
If versioning is being used, then determine any API version for the
incoming request. Returns a two-tuple of (version, versioning_scheme)
"""
if self.versioning_class is None:
return (None, None)
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)

(4)versioning_class

URLPathVersioning源码

class URLPathVersioning(BaseVersioning):
"""
To the client this is the same style as `NamespaceVersioning`.
The difference is in the backend - this implementation uses
Django's URL keyword arguments to determine the version. An example URL conf for two views that accept two different versions. urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
] GET /1.0/something/ HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in URL path.') def determine_version(self, request, *args, **kwargs):
version = kwargs.get(self.version_param, self.default_version)
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request.version is not None:
kwargs = {} if (kwargs is None) else kwargs
kwargs[self.version_param] = request.version return super(URLPathVersioning, self).reverse(
viewname, args, kwargs, request, format, **extra
)

可以看到

(1)url配置

(2)determine_version

里面有个is_allowed_version,点进去可以看到一些基本参数 (继承BaseVersioning基类)

class BaseVersioning(object):
#默认的版本
default_version = api_settings.DEFAULT_VERSION
#允许的版本
allowed_versions = api_settings.ALLOWED_VERSIONS
#默认参数(是version,比如你可以自定义为v)
version_param = api_settings.VERSION_PARAM def determine_version(self, request, *args, **kwargs):
msg = '{cls}.determine_version() must be implemented.'
raise NotImplementedError(msg.format(
cls=self.__class__.__name__
)) def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
return _reverse(viewname, args, kwargs, request, format, **extra) def is_allowed_version(self, version):
if not self.allowed_versions:
return True
return ((version is not None and version == self.default_version) or
(version in self.allowed_versions))

Django rest framework源码分析(4)----版本的更多相关文章

  1. Django rest framework源码分析(3)----节流

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  2. Django rest framework源码分析(1)----认证

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  3. Django rest framework 源码分析 (1)----认证

    一.基础 django 2.0官方文档 https://docs.djangoproject.com/en/2.0/ 安装 pip3 install djangorestframework 假如我们想 ...

  4. Django rest framework源码分析(一) 认证

    一.基础 最近正好有机会去写一些可视化的东西,就想着前后端分离,想使用django rest framework写一些,顺便复习一下django rest framework的知识,只是顺便哦,好吧. ...

  5. Django rest framework源码分析(2)----权限

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  6. 3---Django rest framework源码分析(3)----节流

    Django rest framework源码分析(3)----节流 目录 添加节流 自定义节流的方法  限制60s内只能访问3次 (1)API文件夹下面新建throttle.py,代码如下: # u ...

  7. Django之REST framework源码分析

    前言: Django REST framework,是1个基于Django搭建 REST风格API的框架: 1.什么是API呢? API就是访问即可获取数据的url地址,下面是一个最简单的 Djang ...

  8. Django搭建及源码分析(三)---+uWSGI+nginx

    每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...

  9. Django Rest Framework源码剖析(八)-----视图与路由

    一.简介 django rest framework 给我们带来了很多组件,除了认证.权限.序列化...其中一个重要组件就是视图,一般视图是和路由配合使用,这种方式给我们提供了更灵活的使用方法,对于使 ...

随机推荐

  1. MySQL单表百万数据记录分页性能优化,转载

    背景: 自己的一个网站,由于单表的数据记录高达了一百万条,造成数据访问很慢,Google分析的后台经常报告超时,尤其是页码大的页面更是慢的不行. 测试环境: 先让我们熟悉下基本的sql语句,来查看下我 ...

  2. gulp配置

    /* gulp配置 */ /* gulp配置 */ var gulp = require('gulp'), concat = require('gulp-concat'), rename = requ ...

  3. mysql性能分析之explain的用法

    之前是一直没有听过explain这个关键字的, 最近因为项目中总是会有慢查询的一些操作, 所以请教了旁边的同事帮忙排查下原因, 看到同事用explain来分析一些sql语句, 感觉好像发现了新大陆一样 ...

  4. OpenStack Paste.ini详解(一)

    问题背景 最近在研究openstack 服务的源代码,由于项目代码较多对其又不熟悉,刚开始就不知道从哪里开始入手分析.经过分析发现,在正式分析源码之前需要对python的wsgi.paste.rout ...

  5. 九度oj题目1002:Grading

    //不是说C语言就是C++的子集么,为毛printf在九度OJ上不能通过编译,abs还不支持参数为整型的abs()重载 //C++比较正确的做法是#include<cmath.h>,cou ...

  6. 叮咚recovery——想刷什么包就刷什么包

    我手机vivo s11t,我之前试过刷机,刷过很多包,发现只有官网下载的相同版本的固件包可以成功刷入,其他的任何的包都不行,我弟弟的手机vivo x3L,遇见和我一样的情况,他想刷小米的MIUI,开始 ...

  7. 修改WordPress后台登录地址,提高安全性

    大家都知道,WordPress默认的后台登陆地址是http://[你的域名]/wp-admin,今天就来讲讲怎么修改WordPress后台登录地址,首先要知道为什么要修改WordPress后台登录地址 ...

  8. windows中安装redis

    Redis是有名的NoSql数据库,一般Linux都会默认支持.但在Windows环境中, Windows的Redis安装包需要到以下GitHub链接找到.链接:https://github.com/ ...

  9. yum安装puppet

    yum安装puppet author:headsen chen     2017-10-31  17:09:35 个人原创,转载请注明作者和出处,否则依法追究法律责任: 环境:centos 6.5 [ ...

  10. IE浏览器清除缓存没用

    再想买更新JS和css文件之后, 使用 internet 里面的删除选项 发现样式和事件还是没用变 最终发现 需要 按 f12 找到这个清缓存才正常解决问题