因此,谷歌一下,似乎普遍的共识是,在REST URI中嵌入版本号是一种糟糕的做法,也是一个糟糕的想法。
尽管如此,还是有强烈的支持者支持这一点。
例如Best practices for API versioning?
我的问题是如何使用django-rest-framework中的accept header / content协商来实现所提出的解决方案。
它看起来像框架中的内容协商,
http://django-rest-framework.org/api-guide/content-negotiation/已配置为根据接受的MIME类型自动返回目标值。如果我开始使用自定义类型的Accept头,我将失去框架的这一好处。
在框架中有没有更好的方法来实现这一点?
发布于 2013-01-17 21:17:23
这样做的一种方法是将版本控制指定为媒体类型的一部分。
这就是GitHub currently do for their API。
您还可以在accept标头中包含媒体类型参数,例如Accept: application/json; version=beta,这将成功匹配JSONRenderer。然后,您可以根据接受的媒体类型对视图进行编码,使其具有不同的行为,请参见here。
在API中有许多不同的版本控制模式,我不会说围绕正确的方法有任何伟大的共识,但这是一种合理的可能性。
更新2015年1月:3.1.0版本中将引入更好的版本支持。查看此拉取请求
更新2015年3月:版本控制API are now available的文档。
(https://github.com/tomchristie/django-rest-framework/pull/2285)了解更多详细信息。
发布于 2014-02-18 05:42:45
更新:
versioning现在得到了正确的支持。
以下是您的链接中的一些答案:
我们发现把版本放在网址中是实用和有用的。它让你很容易一眼就知道你在用什么。我们将别名/foo添加到/foo/(最新版本),以便于使用,更短/更干净的URL,等等,正如公认的答案所建议的那样。永远保持向后兼容性通常是成本高昂和/或非常困难的。我们更喜欢提前通知弃用,重定向,文档和其他机制。
因此,我们采用了这种方法,并允许客户端在请求头(X- version )中指定版本,下面是我们是如何做到的:
API应用程序中的结构:
.
├── __init__.py
├── middlewares.py
├── urls.py
├── v1
│ ├── __init__.py
│ ├── account
│ │ ├── __init__.py
│ │ ├── serializers.py
│ │ └── views.py
│ └── urls.py
└── v2
├── __init__.py
├── account
│ ├── __init__.py
│ ├── serializers.py
│ └── views.py
└── urls.pyproject urls.py:
url(r'^api/', include('project.api.urls', namespace='api')),接口应用层urls.py:
from django.conf.urls import *
urlpatterns = patterns('',
url(r'', include('project.api.v2.urls', namespace='default')),
url(r'^v1/', include('project.api.v1.urls', namespace='v1')),
)版本级别urls.py
from django.conf.urls import *
from .account import views as account_views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('account', account_views.AccountView)
router.register('myaccount', account_views.MyAccountView)
urlpatterns = router.urls创建一个中间件,通过更改path_info来切换到正确的代码,请注意,在项目级urls中定义的命名空间('api')是不灵活的,需要在中间件中知道:
from django.core.urlresolvers import resolve
from django.core.urlresolvers import reverse
class VersionSwitch(object):
def process_request(self, request):
r = resolve(request.path_info)
version = request.META.get('HTTP_X_VERSION', False)
if r.namespace.startswith('api:') and version:
old_version = r.namespace.split(':')[-1]
request.path_info = reverse('{}:{}'.format(r.namespace.replace(old_version, version), r.url_name), args=r.args, kwargs=r.kwargs)示例url:
curl -H "X-Version: v1" http://your.domain:8000/api/myaccount/发布于 2021-04-13 22:50:54
@James Lin给了一个很好的回答。在对答案的评论中,@Mar0ux询问了如何处理损坏的HyperlinkedRelatedField字段。
我修复了这个问题,将HyperlinkedRelatedField更改为SerializerMethodField,并通过向其传递额外的参数current_app来调用reverse (非常不明显)。
例如,我有一个应用程序'fruits_ app ',命名空间版本为'v1','v2‘。我有水果模型的序列化程序。因此,为了序列化url,我创建了一个字段
url = serializers.SerializerMethodField()和相应的方法:
def get_url(self, instance):
reverse.reverse('fruits_app:fruit-detail',
args=[instance.pk],
request=request,
current_app=request.version)对于嵌套的名称空间,您将需要更改,将这些名称空间添加到current_app。例如,如果你有一个应用程序'fruits_app‘,其命名空间版本为'v1','v2',实例命名空间为'bananas’,则序列化水果url的方法如下所示:
def get_url(self, instance):
reverse.reverse('fruits_app:fruit-detail',
args=[instance.pk],
request=request,
current_app='bananas:{}'.format(request.version))https://stackoverflow.com/questions/14269719
复制相似问题