准备
新建一个项目,采用路由分发的方式,采用之前的数据库表的例子并添加修改
目录结构如下:
demo
api
migrations
__init__.py
__init__.py
admin.py
apps.py
models.py
tests.py
urls.py # 路由分发后的urls
views.py
demo
__init__.py
settings.py
urls.py
wsgi.py
templates
db.sqlite3
manage.py
# demoapimodels.py
from django.db import models
class UserGroup(models.Model):
title = models.CharField(max_length=32)
class UerInfo(models.Model):
user_type_choices = (
(1, '普通用户'),
(2, 'VIP'),
(3, 'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=64)
roles = models.ManyToManyField("Role")
group = models.ForeignKey("UserGroup")
class UserToken(models.Model):
user = models.OneToOneField(to='UerInfo')
token = models.CharField(max_length=64)
class Role(models.Model):
title = models.CharField(max_length=32)
# demodemourls.py
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^api/', admin.site.urls),
url(r'^api/', include('api.urls')),
]
# demoapiurls.py
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^users/$', views.UsersView.as_view()),
]
# demoapiviews.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class UsersView(APIView):
def get(self, request, *args, **kwargs):
# 通过原生的request
version = request._request.GET.get('version')
print(version)
return HttpResponse("用户列表")
启动项目,在浏览器输入 http://127.0.0.1:8000/api/users/?version=v1
,后台会返回一个 v1
,这是通过访问原生的 request
去获取版本
还有一种方法,通过 query_params
访问
# demoapiviews.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class UsersView(APIView):
def get(self, request, *args, **kwargs):
version = request.query_params.get('version')
print(version)
return HttpResponse("用户列表")
因为这是 query_params
内部自己访问原生的 request
,达到同样的效果
自定义版本组件
URL中通过GET传参
通过上面的 query_params
,可以自定义一个版本的组件,从而获取版本
# demoapiviews.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class ParamVersion(object):
def determine_version(self, request, *args, **kwargs):
version = request.query_params.get('version')
return version
class UsersView(APIView):
versioning_class = ParamVersion
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse("用户列表")
启动项目,在浏览器输入 http://127.0.0.1:8000/api/users/?version=v2
,后台会返回一个 v2
还可以使用内置的方法去获取版本
# demoapiviews.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import QueryParameterVersioning
class UsersView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse("用户列表")
# 进入 QueryParameterVersioning 查看
class QueryParameterVersioning(BaseVersioning):
"""
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in query parameter.')
def determine_version(self, request, *args, **kwargs):
# 这里的与上面自己所写的几乎相同,并且它还有默认的版本(可以在配置文件中设置)
version = request.query_params.get(self.version_param, self.default_version)
# is_allowed_version是允许的版本
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
# 反向生成URL
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
url = super(QueryParameterVersioning, self).reverse(
viewname, args, kwargs, request, format, **extra
)
if request.version is not None:
return replace_query_param(url, self.version_param, request.version)
return url
可以在配置文件中设置默认的版本
# demodemosettings.py
# 在末尾添加
REST_FRAMEWORK = {
"DEFAULT_VERSION": 'v1', # 默认版本
"ALLOWED_VERSION": ['v1', 'v2'], # 允许使用的版本
"VERSION_PARAM": 'version' # url中的key值
}
现在在浏览器中,只能通过访问 http://127.0.0.1:8000/api/users/
或 http://127.0.0.1:8000/api/users/?version=v1
或 http://127.0.0.1:8000/api/users/?version=v2
的方式从后台获取数据
URL路径中传参(推荐使用)
它也是个内置的方法
# demoapiviews.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import URLPathVersioning
class UsersView(APIView):
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse("用户列表")
因为是通过路径传参,所以在 url 中需要有所改动
# demoapiurls.py
from django.conf.urls import url
from api import views
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view()),
]
这时在浏览器中通过 http://127.0.0.1:8000/api/v1/users/
也可以在后台获取 v1
,这时推荐的使用方式
可以设置在配置文件中,做全局的设置,在视图函数中便可以省略
# demodemosettings.py
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION": 'v1',
"ALLOWED_VERSION": ['v1', 'v2'],
"VERSION_PARAM": 'version'
}
# demoapiviews.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class UsersView(APIView):
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse("用户列表")
源码流程
请求进来,先走 dispatch
,对 request
进行封装,走 initial
def initial(self, request, *args, **kwargs):
... # 省略的内容
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
# 认证、权限、频率
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
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)
# 处理版本类的对象,就是 settings.py中 URLPathVersioning类的对象
scheme = self.versioning_class()
# 返回两个值,第一个是调用determine_version的方法,根据请求获取版本
# 第二个scheme是处理版本的对象
return (scheme.determine_version(request, *args, **kwargs), scheme)
class APIView(View):
... # 省略的内容
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
先处理版本再走认证、权限、频率
反向生成URL
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from django.urls import reverse
class UsersView(APIView):
def get(self, request, *args, **kwargs):
# 1. 获取版本
print(request.version)
# 2. 获取版本处理的对象
print(request.versioning_scheme)
# 反向自动生成URL(你在浏览器访问的url会给你打印出来)
u1 = request.versioning_scheme.reverse(viewname='uu', request=request)
print(u1)
# 手动生成
u2 = reverse(viewname='uu', kwargs={'version':2})
print(u2)
return HttpResponse("用户列表")
总结
使用
配置文件
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'],
"VERSION_PARAM":'version',
}
路由系统
urlpatterns = [
url(r'^api/', admin.site.urls),
url(r'^api/', include('api.urls')),
]
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(), name='uu'),
]
视图
- 获取版本
- 获取版本处理的对象
- 反向生成URL