【问题标题】:Django REST framework - different views for same url depending on http methodDjango REST 框架 - 相同 url 的不同视图取决于 http 方法
【发布时间】:2016-08-31 11:44:12
【问题描述】:

我有一个 REST 框架 API,我必须根据方法将 url 分派到 2 个不同的视图。

架构是这样的:

bookshop/authors/ - lists all authors, with POST - adds an author

bookshop/authors/<author>/ - with GET - gets details for an author, including books

bookshop/authors/<author>/ - with POST - creates a posting of a book for the same author. 

bookshop/authors/<author>/<book>/ - gets a book, no posting

一般来说,对于我的所有 API,我都在使用带有路由器的视图集。

我试过这样做:

urlpatterns = patterns(
    '',
    url(r'^author/(?P<author>[0-9]+)',
        AuthorViewSet.as_view({'get': 'retrieve'}),
        name='author-detail'),
    url(r'^author/(?P<author>[0-9]+)',
        BookViewSet.as_view({'post': 'create'})),
)

但随后它转到第一个 url,视图集检查方法并抛出异常 MethodNotAllowed。

我试着像这样抓住它:

try: 
    urlpatterns = patterns( 
    '', 
    url(r'^author/(?P<author>[0-9]+)',  
    AuthorViewSet.as_view({'get': 'retrieve'}), 
    name='author-detail') 
    ) 
except MethodNotAllowed: 
    urlpatterns = patterns( 
    '', 
    url(r'^author/(?P<author>[0-9]+)', 
    BookViewSet.as_view({'post': 'create'})), 
    )

但它也不起作用。

有没有办法使用视图集来做到这一点?

【问题讨论】:

  • 您收到该错误是因为默认情况下不允许在详细视图上发布帖子......bookshop/authors/&lt;author&gt;/ - with POST 特别是......为什么不将其更改为看跌期权或补丁
  • 在某些情况下它不应该是详细视图,这就是为什么我想为同一个 url 注册两个不同的视图。例如: bookshop/authors/Lindgren/ 如果使用 GET 访问,则为详细视图,如果使用 POST 访问,则应发布(该作者的书,而不是作者)。
  • Django url 的工作方式是,第一个匹配的就是要使用其视图的那个。它不使用该方法来推断要运行的视图。因此,在您的情况下,执行 POSTauthors/Lindgren/ 的第一个视图将始终首先匹配该 URL。在上面的示例中,AuthorViewSet 将用于POSTGET
  • 他们分开工作,每个视图。
  • 没关系。但是BookViewSet 永远不会被使用。因为AuthorViewSet首先匹配,因为它与BookViewSet共享相同的url,而BookViewSet在它之后

标签: django rest django-rest-framework


【解决方案1】:

问题在于,以这种方式组织 API 违反了 RESTful 约定。打破 RESTful 约定并不总是坏事,但通常代表糟糕的设计,当然意味着更难使用围绕 restframework 设计的第 3 方软件来支持您的模式。所以我的建议是将您的 API 架构更新为:

GET  bookshop/authors/ - lists all authors
POST bookshop/authors/ - creates an author
GET  bookshop/authors/<author>/ - gets details for an author
POST bookshop/authors/<author>/books/ - creates a book for an author
GET  bookshop/authors/<author>/books/<book> - gets a book

如果您需要添加帖子,您也可以拥有(我不确定对象之间的关系,所以不确定下面是否准确地表示了这种关系)。

POST bookshop/authors/<author>/books/<book>/postings - creates a posting
GET  bookshop/authors/<author>/books/<book>/postings/<posting> - gets a posting

【讨论】:

  • 我通过覆盖视图集并根据 HTTP 方法在两个序列化程序之间进行选择来解决这个问题。我不想更改 API 结构的原因是它很好地增加了项目中更广泛的逻辑结构(它真的不是作者和书籍 :))
  • 但实际上你的回答很有道理,所以我会赞成它,但不接受它,对不起
  • 并且,对于这种情况下的restful约定,API不会被第三方访问(至少现在不是计划),只能从我们自己的javascript应用程序访问,所以也许不是那么这是一个大问题。
  • 有道理。需要注意的是,打破惯例通常也会使内部前端应用程序也更难使用 API。例如,像 Restangular 这样的角度服务期望 api 使用 restful 约定。打破该约定会使使用 Restangular 或类似服务变得更加困难。并且涉及对服务进行一点黑客攻击或不使用它。
【解决方案2】:

当使用Viewsets 时,通常您会希望使用路由器注册您的视图,而不是像之前那样直接绑定视图。路由器将负责将请求“路由”到正确的处理程序。

结帐:

http://www.django-rest-framework.org/api-guide/viewsets/#example

http://www.django-rest-framework.org/api-guide/routers/

【讨论】:

  • 我正在向路由器注册我的所有其他视图,但在这种特殊情况下,由于 API 的体系结构,我不能这样做。这是因为这些视图集是重叠的。如果我这样做: router.register(r^'authors',AuthorsViewSet) 那么它会绑定一个url authors/?P 和一个get-detail方法,我不能再次使用相同的链接对于 POST。阅读更多问题和给定的例子:)无论如何,我通过为这两种情况创建一个视图来解决这个问题,只选择
  • 其实我是先用路由器做的,后来看到不能做的时候,我想我可能会设法像这样注册它们,但我也做不到.
  • 啊,没有简单的方法可以做到这一点。我不会,因为它打破了宁静的惯例。而是尝试:
  • 实际上,让我创建一个新的答案来解决这个问题
猜你喜欢
  • 1970-01-01
  • 2015-12-19
  • 2020-10-10
  • 2021-11-21
  • 1970-01-01
  • 2017-10-25
  • 2021-01-14
  • 2014-05-02
  • 2019-06-22
相关资源
最近更新 更多