官方原文連接
本系列文章 github 地址
轉載請註明出處python
API 版本控制容許你更改不一樣客戶端之間的行爲。 REST framework 提供了許多不一樣的版本控制方案。git
版本控制由傳入的客戶端請求決定,可能基於請求 URL 或請求 header。github
有幾種有效的方法來處理版本控制。非版本化的系統也多是合適的,特別是若是你正在爲超出控制範圍的多個客戶端的很是長期的系統進行工程設計。正則表達式
當啓用 API 版本控制時, request.version
屬性將包含一個對應於傳入客戶端請求的版本的字符串。django
默認狀況下,版本控制未啓用,request.version
將始終返回 None
。json
如何改變 API 的行爲取決於你,但你可能一般須要的一個示例是在新版本中切換到不一樣的序列化樣式。例如:api
def get_serializer_class(self):
if self.request.version == 'v1':
return AccountSerializerVersion1
return AccountSerializer
複製代碼
REST framework 包含的 reverse
函數與版本控制方案相關聯。你須要確保將當前請求包含爲關鍵字參數,以下所示。bash
from rest_framework.reverse import reverse
reverse('bookings-list', request=request)
複製代碼
上述功能將應用適合請求版本的任何 URL 轉換。例如:服務器
NamespacedVersioning
,而且 API 版本爲 'v1',則使用的 URL lookup 將爲 'v1:bookings-list'
,可能會解析爲像 http://example.org/v1/bookings/
這樣的 URL。QueryParameterVersioning
,而且 API 版本爲 1.0
,則返回的 URL 可能與 http://example.org/bookings/?version=1.0
相似將超連接序列化樣式與基於 URL 的版本控制方案一塊兒使用時,請確保將請求做爲上下文包含在序列化類中。app
def get(self, request):
queryset = Booking.objects.all()
serializer = BookingsSerializer(queryset, many=True, context={'request': request})
return Response({'all_bookings': serializer.data})
複製代碼
這樣作將容許任何返回的 URL 包含合適的版本。
版本控制方案由 DEFAULT_VERSIONING_CLASS
setting key 定義。
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
}
複製代碼
除非明確設置,不然 DEFAULT_VERSIONING_CLASS
的值將爲 None
。在這種狀況下,request.version
屬性將始終返回 None
。
你還能夠在單個視圖上設置版本控制方案。一般,您不須要這樣作,由於全局使用單個版本控制方案更有意義。若是你確實須要這樣作,請使用 versioning_class
屬性。
class ProfileList(APIView):
versioning_class = versioning.QueryParameterVersioning
複製代碼
如下 settings key 也用於控制版本控制:
DEFAULT_VERSION
. 當沒有版本信息存在時,用於 request.version
的值。默認爲 None
。ALLOWED_VERSIONS
. 若是設置,則此值將限制版本控制方案可能返回的版本集,若是提供的版本不在此集中,則會引起錯誤。請注意,用於 DEFAULT_VERSION
設置的值始終被認爲是 ALLOWED_VERSIONS
集的一部分(除非它是 None
)。默認爲 None
。VERSION_PARAM
. 應該用於任何版本控制參數的字符串,例如媒體類型或 URL 查詢參數。默認爲 'version'
。你還能夠經過定義本身的版本控制方案並使用 default_version
,allowed_versions
和 version_param
類變量,在每一個視圖或每一個視圖集的基礎上設置版本控制類以及這三個值。例如,若是你想使用 URLPathVersioning
:
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIView
class ExampleVersioning(URLPathVersioning):
default_version = ...
allowed_versions = ...
version_param = ...
class ExampleView(APIVIew):
versioning_class = ExampleVersioning
複製代碼
此方案要求客戶端將版本指定爲 Accept
header 中媒體類型的一部分。該版本做爲媒體類型參數包含在內,它補充了主要媒體類型。
這是一個使用 accept header 版本風格的示例 HTTP 請求。
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
複製代碼
在上面的示例請求中 request.version
屬性將返回字符串 '1.0'
。
基於 Accept header 的版本控制一般被認爲是最佳實踐,儘管其餘樣式可能更適合你的客戶端需求。
嚴格地說,json
media type 不能被指定爲包含附加參數。若是你正在構建精心指定的公共 API,則能夠考慮使用vendor media type。爲此,請將你的渲染器配置爲使用基於 JSON 的渲染器和自定義 media type:
class BookingsAPIRenderer(JSONRenderer):
media_type = 'application/vnd.megacorp.bookings+json'
複製代碼
客戶端請求如今看起來像這樣:
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/vnd.megacorp.bookings+json; version=1.0
複製代碼
該方案要求客戶端將版本指定爲 URL 路徑的一部分。
GET /v1/bookings/ HTTP/1.1
Host: example.com
Accept: application/json
複製代碼
你的 URL conf 必須包含一個與 'version'
關鍵字參數相匹配的模式,以便版本控制方案可使用此信息。
urlpatterns = [
url(
r'^(?P<version>(v1|v2))/bookings/$',
bookings_list,
name='bookings-list'
),
url(
r'^(?P<version>(v1|v2))/bookings/(?P<pk>[0-9]+)/$',
bookings_detail,
name='bookings-detail'
)
]
複製代碼
對於客戶端來講,這個方案與 URLPathVersioning
相同。惟一的區別是,它是如何在 Django 應用程序中配置的,由於它使用 URL 命名空間而不是 URL 關鍵字參數。
GET /v1/something/ HTTP/1.1
Host: example.com
Accept: application/json
複製代碼
使用此方案,request.version
屬性是根據與傳入請求路徑匹配的 namespace
肯定的。
在下面的例子中,咱們給出了一組視圖兩個不一樣的可能的 URL 前綴,每一個前綴在不一樣的命名空間下:
# bookings/urls.py
urlpatterns = [
url(r'^$', bookings_list, name='bookings-list'),
url(r'^(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail')
]
# urls.py
urlpatterns = [
url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))
]
複製代碼
若是你只須要簡單的版本控制方案,那麼 URLPathVersioning
和 NamespaceVersioning
都是能夠的。 URLPathVersioning
方法可能更適合於小型項目,NamespaceVersioning
可能更容易管理大型項目。
hostname 版本控制方案要求客戶端將請求的版本指定爲 URL 中 hostname 的一部分。
例如,如下是對 http://v1.example.com/bookings/
URL 的 HTTP 請求:
GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json
複製代碼
默認狀況下,這個實現指望 hostname 匹配這個簡單的正則表達式:
^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
複製代碼
請注意,第一組用括號括起來,表示這是 hostname 的匹配部分。
HostNameVersioning
方案在調試模式下可能會很笨拙,由於你一般會訪問諸如 127.0.0.1
的原始 IP 地址。
若是你有要求根據版本將傳入請求路由到不一樣的服務器,那麼基於 hostname 的版本控制就會特別有用,由於你能夠爲不一樣的 API 版本配置不一樣的 DNS 記錄。
該方案是一種簡單的風格,其中包含版本做爲 URL 中的查詢參數。例如:
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
複製代碼
要實現自定義版本控制方案,請繼承 BaseVersioning
並覆蓋 .determine_version
方法。
如下示例使用自定義的 X-API-Version
header 來肯定所請求的版本。
class XAPIVersionScheme(versioning.BaseVersioning):
def determine_version(self, request, *args, **kwargs):
return request.META.get('HTTP_X_API_VERSION', None)
複製代碼
若是你的版本控制方案基於請求 URL,則還須要更改版本化 URL 的肯定方式。爲了作到這一點,你應該重寫類的 .reverse()
方法。有關示例,請參閱源代碼。