DRF 版本控制 #

一、版本控制概述 #

1.1 为什么需要版本控制 #

  • API接口变更时保持向后兼容
  • 允许客户端逐步迁移
  • 支持多版本并存

1.2 版本控制方式 #

方式 说明 示例
URLPathVersioning URL路径 /api/v1/articles/
NamespaceVersioning URL命名空间 /v1/articles/
HostNameVersioning 域名 v1.api.example.com
QueryParameterVersioning 查询参数 /api/articles/?version=1
AcceptHeaderVersioning Accept头 Accept: application/json; version=1

二、URLPathVersioning #

2.1 配置 #

python
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'DEFAULT_VERSION': 'v1',
    'ALLOWED_VERSIONS': ['v1', 'v2'],
    'VERSION_PARAM': 'version',
}

2.2 URL配置 #

python
urlpatterns = [
    path('api/<str:version>/articles/', ArticleViewSet.as_view({'get': 'list'})),
]

2.3 访问方式 #

text
GET /api/v1/articles/
GET /api/v2/articles/

2.4 视图中获取版本 #

python
class ArticleViewSet(viewsets.ModelViewSet):
    def get_serializer_class(self):
        version = self.request.version
        if version == 'v1':
            return ArticleSerializerV1
        return ArticleSerializerV2

三、QueryParameterVersioning #

3.1 配置 #

python
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning',
    'DEFAULT_VERSION': 'v1',
    'ALLOWED_VERSIONS': ['v1', 'v2'],
    'VERSION_PARAM': 'version',
}

3.2 访问方式 #

text
GET /api/articles/?version=v1
GET /api/articles/?version=v2

四、AcceptHeaderVersioning #

4.1 配置 #

python
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning',
    'DEFAULT_VERSION': 'v1',
    'ALLOWED_VERSIONS': ['v1', 'v2'],
}

4.2 访问方式 #

bash
curl -H "Accept: application/json; version=v1" http://api.example.com/articles/
curl -H "Accept: application/json; version=v2" http://api.example.com/articles/

五、版本化ViewSet #

5.1 多版本ViewSet #

python
class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    
    def get_serializer_class(self):
        version = self.request.version
        if version == 'v1':
            return ArticleSerializerV1
        elif version == 'v2':
            return ArticleSerializerV2
        return ArticleSerializer
    
    def get_queryset(self):
        queryset = Article.objects.all()
        version = self.request.version
        
        if version == 'v1':
            queryset = queryset.filter(is_published=True)
        
        return queryset

5.2 版本化URL #

python
from rest_framework.routers import DefaultRouter
from .views import ArticleV1ViewSet, ArticleV2ViewSet

router_v1 = DefaultRouter()
router_v1.register(r'articles', ArticleV1ViewSet)

router_v2 = DefaultRouter()
router_v2.register(r'articles', ArticleV2ViewSet)

urlpatterns = [
    path('api/v1/', include(router_v1.urls)),
    path('api/v2/', include(router_v2.urls)),
]

六、版本弃用 #

6.1 弃用警告 #

python
from rest_framework.response import Response

class ArticleViewSet(viewsets.ModelViewSet):
    def list(self, request, *args, **kwargs):
        response = super().list(request, *args, **kwargs)
        
        if request.version == 'v1':
            response['X-API-Deprecated'] = 'This version is deprecated. Please migrate to v2.'
        
        return response

6.2 版本过期处理 #

python
from rest_framework.exceptions import APIException

class VersionExpired(APIException):
    status_code = 410
    default_detail = '此API版本已过期,请使用最新版本'

class ArticleViewSet(viewsets.ModelViewSet):
    def initial(self, request, *args, **kwargs):
        if request.version == 'v0':
            raise VersionExpired()
        super().initial(request, *args, **kwargs)

七、总结 #

本章学习了DRF版本控制:

  • URLPathVersioning:URL路径版本
  • QueryParameterVersioning:查询参数版本
  • AcceptHeaderVersioning:请求头版本
  • 版本化ViewSet:多版本视图
  • 版本弃用:弃用和过期处理

版本控制让API演进更加平滑!

最后更新:2026-03-28