【问题标题】:Removing the list endpoint from a resource on tastypie从美味派上的资源中删除列表端点
【发布时间】:2013-05-16 02:36:16
【问题描述】:

我的 api 上有一个始终返回登录用户的资源。该资源是只读的。 我希望列表 uri 充当详细 uri,并删除详细 url。

因此,/api/v1/user/ 将返回登录的用户,而任何其他 url 都会失败。 这就是我为实现这一目标所做的:

class UserResource(ModelResource):
    class Meta:
        queryset = User.objects.all()
        fields = ['email', 'name']
        authentication = MultiAuthentication(SessionAuthentication(), BasicAuthentication())
        authorization = Authorization()
        list_allowed_methods = []
        detail_allowed_methods = ['get']

    def base_urls(self):
        '''
        The list endpoint behaves as the list endpoint.
        '''
        return [
            url(r"^(?P<resource_name>%s)%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
            url(r"^(?P<resource_name>%s)/schema%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_schema'), name="api_get_schema")
        ]

    def obj_get(self, bundle, **kwargs):
        '''
        Always returns the logged in user.
        '''
        return bundle.request.user

    def get_resource_uri(self, bundle_or_obj=None, url_name='api_dispatch_detail'):
        bundle_or_obj = None
        try:
            return self._build_reverse_url(url_name, kwargs=self.resource_uri_kwargs(bundle_or_obj))
        except NoReverseMatch:
            return ''

我使用base_urls() 而不是prepend_urls(),因为我想删除其他网址。

它工作正常,但是当我点击/api/v1/ url 时,我收到了这个错误:

Traceback:
File "/home/vagrant/workspace/expenses/venv/local/lib/python2.7/site-packages/Django-1.5-py2.7.egg/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/workspace/expenses/venv/local/lib/python2.7/site-packages/django_tastypie-0.9.15-py2.7.egg/tastypie/api.py" in wrapper
  80.                 return getattr(self, view)(request, *args, **kwargs)
File "/home/vagrant/workspace/expenses/venv/local/lib/python2.7/site-packages/django_tastypie-0.9.15-py2.7.egg/tastypie/api.py" in top_level
  137.                     'resource_name': name,
File "/home/vagrant/workspace/expenses/venv/local/lib/python2.7/site-packages/django_tastypie-0.9.15-py2.7.egg/tastypie/api.py" in _build_reverse_url
  166.         return reverse(name, args=args, kwargs=kwargs)
File "/home/vagrant/workspace/expenses/venv/local/lib/python2.7/site-packages/Django-1.5-py2.7.egg/django/core/urlresolvers.py" in reverse
  496.     return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
File "/home/vagrant/workspace/expenses/venv/local/lib/python2.7/site-packages/Django-1.5-py2.7.egg/django/core/urlresolvers.py" in _reverse_with_prefix
  416.                 "arguments '%s' not found." % (lookup_view_s, args, kwargs))

Exception Type: NoReverseMatch at /api/v1/
Exception Value: Reverse for 'api_dispatch_list' with arguments '()' and keyword arguments '{'api_name': u'v1', 'resource_name': 'user'}' not found.

它正在尝试到达丢失的列表端点。我该如何摆脱它?

谢谢。


感谢 Rudy 的指导,我最终得到了以下结果:

class UserResource(ModelResource):
    class Meta:
        queryset = User.objects.all()
        fields = ['email', 'name']
        authentication = MultiAuthentication(SessionAuthentication(), BasicAuthentication())
        authorization = Authorization()
        list_allowed_methods = []
        detail_allowed_methods = ['get']

    def dispatch_list(self, request, **kwargs):
        return self.dispatch_detail(request, **kwargs)

    def obj_get(self, bundle, **kwargs):
        '''
        Always returns the logged in user.
        '''
        return bundle.request.user

    def get_resource_uri(self, bundle_or_obj=None, url_name='api_dispatch_list'):
        bundle_or_obj = None
        try:
            return self._build_reverse_url(url_name, kwargs=self.resource_uri_kwargs(bundle_or_obj))
        except NoReverseMatch:
            return ''

【问题讨论】:

    标签: python rest tastypie


    【解决方案1】:

    您应该使用一个自定义的 Authorization 类来阻止列表端点并优雅地引发错误,而不是仅仅一起删除 URL,这样它仍然可以很好地与 Tastypie 配合使用。

    class UserObjectsOnlyAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        raise Unauthorized("Sorry, no list reads.")
    
    def read_detail(self, object_list, bundle):
        # Is the requested object the user?
        return bundle.obj == bundle.request.user
    
    def create_list(self, object_list, bundle):
        raise Unauthorized("Sorry, no creates.")
    
    def create_detail(self, object_list, bundle):
        raise Unauthorized("Sorry, no creates.")
    
    def update_list(self, object_list, bundle):
        raise Unauthorized("Sorry, no updates.")
    
    def update_detail(self, object_list, bundle):
        raise Unauthorized("Sorry, no updates.")
    
    def delete_list(self, object_list, bundle):
        # Sorry user, no deletes for you!
        raise Unauthorized("Sorry, no deletes.")
    
    def delete_detail(self, object_list, bundle):
        raise Unauthorized("Sorry, no deletes.")
    

    编辑:

    如果您想强制此 API 始终为“详细信息”请求,那么您可以覆盖 Tastypie 的内置函数。基本上,如果您在 URL 中指定一个 ID,那么美味派将其路由为 _detail 请求,如果您不指定,则将其路由为 _list 请求。如果您覆盖检测到这一点的调度函数,您可以将对该资源的所有请求更改为 _detail 并指定查找用户的主键。这可能有点 hacky,但会完成你想要的:

    def dispatch(self, request_type, request, **kwargs):
        # Force this to be a single User object
        return super(UserResource, self).dispatch('detail', request, **kwargs)
    
    def get_detail(self, request, **kwargs):
        # Place the authenticated user's id in the get detail request
        kwargs['id'] = request.user.pk
        return super(UserResource, self).get_detail(request, **kwargs)
    

    【讨论】:

    • 但我仍然希望列表端点 url 充当详细端点:/api/v1/user 必须返回一个用户。无需指定用户 id,因为 api 将始终返回 sabe 对象。
    • 编辑添加到我的答案以强制这是一个“详细”响应而不是一个“列表”,即使没有为资源指定主键。
    • 我已经完全删除列表端点并按照您的建议做了一些事情:将列表端点转换为详细端点。不完全是我想要的,但更简单、更干净。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 2012-12-17
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    相关资源
    最近更新 更多