关键词:
【中文标题】django-rest-framework: api 版本控制【英文标题】:django-rest-framework: api versioning 【发布时间】:2012-12-25 12:52:55 【问题描述】:谷歌搜索似乎普遍认为,在 REST URI 中嵌入版本号是一种不好的做法和一个坏主意。
即使在 SO 上,也有强烈的支持者支持这一点。 例如Best practices for API versioning?
我的问题是关于如何完成建议的解决方案,即在 django-rest-framework 中使用接受标头/内容协商来完成此任务。
看起来像是框架中的内容协商,http://django-rest-framework.org/api-guide/content-negotiation/ 已配置为根据接受的 MIME 类型自动返回预期值。如果我开始对自定义类型使用 Accept 标头,我将失去框架的这种好处。
在框架中是否有更好的方法来实现这一点?
【问题讨论】:
【参考方案1】:@James Lin 给出了很好的答案。在 cmets 中回答 @Mar0ux 询问如何处理损坏的 HyperlinkedRelatedField
字段。
我通过将HyperlinkedRelatedField
更改为SerializerMethodField
并调用reverse
解决了这个问题,非常不明显,将额外的参数current_app
传递给它。
例如,我有一个应用程序“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”,则序列化 Fruit url 的方法如下所示:
def get_url(self, instance):
reverse.reverse('fruits_app:fruit-detail',
args=[instance.pk],
request=request,
current_app='bananas:'.format(request.version))
【讨论】:
【参考方案2】:更新:
versioning 现已得到适当支持。
您的链接中有一些答案:
我们发现将版本放在 URL 中既实用又有用。它 让您一目了然地知道您正在使用什么。我们做别名 /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.py
项目 urls.py:
url(r'^api/', include('project.api.urls', namespace='api')),
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 来切换到正确的代码,请注意项目级 url 中定义的命名空间 ('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)
示例网址:
curl -H "X-Version: v1" http://your.domain:8000/api/myaccount/
【讨论】:
这种方法很好,除了它会破坏超链接字段(HyperlinkedRelatedField
等)。有什么想法吗?
我还没有项目设置可以使用HyperlinkedRelatedField
我猜你的问题是如果你指定了不同的版本,链接会转到默认版本?
没错。我倾向于使用 Accept
标头版本控制方法,这样 URL 根本不会改变。
恐怕没有简单的方法可以解决,直到版本控制被烘焙到包中,所以它会生成HyperlinkedRelatedField
的版本感知网址
那么我们把模型放在哪里呢?【参考方案3】:
这样做的一种方法是将版本控制指定为媒体类型的一部分。
这是 GitHub currently do for their API。
您还可以在接受标头中包含媒体类型参数,例如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) 了解更多详情。
【讨论】:
显然这个问题已经赢得了一个受欢迎的问题徽章,只是意识到我从未接受过答案。感谢您在 Tom 框架上的所有辛勤工作!记录对 django-rest-framework 的请求
】记录对django-rest-framework的请求【英文标题】:Loggingrequeststodjango-rest-framework【发布时间】:2013-03-1219:37:12【问题描述】:出于调试目的,我想使用Django的日志记录机制来记录每个“到达”django-rest-framework门口的传入请求。Djagno... 查看详情
django-rest-framework:如何序列化已经包含 JSON 的字段?
】django-rest-framework:如何序列化已经包含JSON的字段?【英文标题】:django-rest-framework:HowDoISerializeaFieldThatAlreadyContainsJSON?【发布时间】:2014-04-0501:41:03【问题描述】:我对django-rest-framework还是很陌生,所以需要一些帮助。我有一... 查看详情
django-rest-framework: api 版本控制
】django-rest-framework:api版本控制【英文标题】:django-rest-framework:apiversioning【发布时间】:2012-12-2512:52:55【问题描述】:谷歌搜索似乎普遍认为,在RESTURI中嵌入版本号是一种不好的做法和一个坏主意。即使在SO上,也有强烈的支持... 查看详情
django-rest-framework 按日期过滤=无
】django-rest-framework按日期过滤=无【英文标题】:django-rest-frameworkfilterbydate=None【发布时间】:2014-02-2611:35:00【问题描述】:我正在使用django-rest-framework和django-filter。我需要检索date属性为None的小部件列表,但无论我尝试什么查询... 查看详情
django-rest-framework、多表模型继承、ModelSerializers 和嵌套序列化器
】django-rest-framework、多表模型继承、ModelSerializers和嵌套序列化器【英文标题】:django-rest-framework,multitablemodelinheritance,ModelSerializersandnestedserializers【发布时间】:2014-07-2518:17:22【问题描述】:我在文档或互联网上找不到此信息。... 查看详情
为啥 django-rest-framework 不显示 OneToOneField 数据 - django
】为啥django-rest-framework不显示OneToOneField数据-django【英文标题】:Whydjango-rest-frameworkdoesn\'tdisplayOneToOneFielddata-django为什么django-rest-framework不显示OneToOneField数据-django【发布时间】:2018-02-1616:26:13【问题描述】:我想在我的网站中... 查看详情
django-rest-framework:每个 ViewSet 可以有多个模板吗?
】django-rest-framework:每个ViewSet可以有多个模板吗?【英文标题】:django-rest-framework:CanIhavemultipletemplatesperViewSet?【发布时间】:2020-07-0701:30:04【问题描述】:我为我的模型创建了一个序列化程序和ViewSet,并为列表视图添加了一个... 查看详情
我无法使用 Django-Rest-Framework 注册用户
】我无法使用Django-Rest-Framework注册用户【英文标题】:IcannotregisterauserusingDjango-Rest-Framework【发布时间】:2021-04-0621:11:54【问题描述】:我无法使用DjangoRestFramework添加新用户。这是我的models.py代码:classProfile(models.Model):user=models.O... 查看详情
使用 django-rest-framework 创建对象后返回 id 值
】使用django-rest-framework创建对象后返回id值【英文标题】:Returningidvalueafterobjectcreationwithdjango-rest-framework【发布时间】:2013-09-1920:32:03【问题描述】:我正在使用django-rest-framework通用视图通过POST请求在模型中创建对象。我想知道... 查看详情
在 django-rest-framework 中捕获参数
】在django-rest-framework中捕获参数【英文标题】:Captureparametersindjango-rest-framework【发布时间】:2014-02-1302:01:42【问题描述】:假设这个网址:http://localhost:8000/articles/1111/comments/我想获取给定文章的所有cmets(此处为1111)。这就是... 查看详情
django-rest-framework 是不是提供管理站点来管理模型?
】django-rest-framework是不是提供管理站点来管理模型?【英文标题】:Doesthedjango-rest-frameworkprovideanadminsitetomanagemodels?django-rest-framework是否提供管理站点来管理模型?【发布时间】:2020-12-1812:02:18【问题描述】:我正在寻找使用djang... 查看详情
Django-rest-framework + React-Admin:URL 反斜杠问题
】Django-rest-framework+React-Admin:URL反斜杠问题【英文标题】:Django-rest-framework+React-Admin:URLBackslashissue【发布时间】:2019-02-0317:59:22【问题描述】:我有一个djangorestapi,它实现了如下突出显示的视图集。classSubjectViewSet(viewsets.ModelView... 查看详情
无法使用视图名称 (django-rest-framework) 解析超链接关系的 URL
】无法使用视图名称(django-rest-framework)解析超链接关系的URL【英文标题】:CouldnotresolveURLforhyperlinkedrelationshipusingviewname(django-rest-framework)【发布时间】:2018-06-2919:50:26【问题描述】:问题:我收到这样的错误。在/api/users/处配置不... 查看详情
在视图集中创建的 Django-rest-framework 权限
】在视图集中创建的Django-rest-framework权限【英文标题】:Django-rest-frameworkpermissionsforcreateinviewset【发布时间】:2014-05-1017:03:02【问题描述】:我正在尝试创建一个RESTAPI并且卡在用户注册上:基本上我需要在注册之前获得访问令牌... 查看详情
django-rest-framework 令牌认证和注销
】django-rest-framework令牌认证和注销【英文标题】:django-rest-frameworkTokenAuthandlogout【发布时间】:2015-03-0707:21:07【问题描述】:据了解,obtain_auth_token视图用作登录功能。您提供凭据并取回令牌。什么会注销?我应该在注销时删除... 查看详情
Django-Rest-Framework 系统检查自定义 HTTP 标头(应用程序 - 令牌)
】Django-Rest-Framework系统检查自定义HTTP标头(应用程序-令牌)【英文标题】:Django-Rest-FrameworksystemtocheckcustomHTTPheader(application-token)【发布时间】:2020-04-1707:05:30【问题描述】:我使用Django和Django-rest-framework。我必须检查一个自定... 查看详情
如何在 django-rest-framework 中对权限进行单元测试?
】如何在django-rest-framework中对权限进行单元测试?【英文标题】:Howtounittestpermissionsindjango-rest-framework?【发布时间】:2016-09-0708:14:14【问题描述】:她的权限是我想要进行单元测试的示例权限。#permissions.pyfrommyapp.modelsimportMembersh... 查看详情
为啥使用 django-rest-framework 时不需要 `csrf_exempt`?
】为啥使用django-rest-framework时不需要`csrf_exempt`?【英文标题】:Whyis`csrf_exempt`notneededwhenusingdjango-rest-framework?为什么使用django-rest-framework时不需要`csrf_exempt`?【发布时间】:2022-01-1323:32:30【问题描述】:当我使用Postman发出POST请... 查看详情