@list_route 和@detail_route 嵌套路由不会出现在 Browseable API 中
@list_route and @detail_route nested routes do not appear in Browseable API
我正在尝试通过 @list_route
和 @detail_route
装饰器使用嵌套路由。路线和 return 数据有效,但我必须在地址栏中手动导航到它们。它们不会出现在 DefaultRouter
生成的 ApiRoot
中可浏览 API。我正在使用 Django 1.8 和 Rest Framework 3.1.1。
在urls.py:
router = DefaultRouter()
router.register(r'aggregates', viewsets.AggregateViewSet, base_name='aggregate')
urlpatterns = [
url(r'^api/', include(router.urls, namespace='myapp')),
]
在viewsets.py:
class AggregateViewSet(viewsets.GenericViewSet):
queryset = models.DataAggregate.objects.order_by('id')
serializer_class = serializers.AggregateSerializer
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
@list_route(url_path='recent')
def recent_aggregates(self, request):
return Response({'message': 'herp a derp'})
当我导航到 /myapp/api
时,可浏览的 API 只显示:
HTTP 200 OK
Content-Type: application/json
Vary: Accept
Allow: GET, HEAD, OPTIONS
{
"aggregates": "http://localhost:8000/myapp/api/aggregates/"
}
我期待这个:
{
"aggregates": "http://localhost:8000/myapp/api/aggregates/"
"aggregates-recent": "http://localhost:8000/myapp/api/aggregates/recent"
}
我试过各种修改版本,看能不能让步,都无济于事。同样,如果我手动导航到这些路由 do 函数和可浏览的 API 将显示它们的页面......但是违背了可浏览的目的 api.
我看了一下 DefaultRouter
(和 SimpleRouter
)的代码,它似乎发现了动态路由...
没错,默认情况下它不会出现在 API 中。
我自己使用该代码段来提供遵循 HAL 样式(py3 代码)的嵌套路由。
import urllib
from collections import OrderedDict
from rest_framework import serializers, relations
class SubNamespaceURLField(relations.HyperlinkedIdentityField):
"""Refers to a child namespace of the object, as pointed by view_name
"""
def __init__(self, namespace, *args, **kwargs):
self.namespace = namespace.strip('/')
super().__init__(*args, **kwargs)
def field_to_native(self, obj, field_name):
base = super().field_to_native(obj, field_name)
return urllib.parse.urljoin(base, self.namespace) + '/'
class HALNestedLinksField(relations.HyperlinkedIdentityField):
""" Tries to represent a list of nested links on the resource a
HAL-compliant way.
See http://stateless.co/hal_specification.html
"""
def __init__(self, endpoints, *args, **kwargs):
"""
:param endpoints list of url suffixes leading to nested operations on
the resource (ex: ['preview', 'check'])
"""
self.endpoints = endpoints
super().__init__(*args, **kwargs)
def get_attribute(self, obj):
return obj
def to_representation(self, value):
links = OrderedDict()
prefix = super().to_representation(self.get_attribute(value))
for i in self.endpoints:
# We consider if it contains a dot its a content-type indication,
# so no trailing slash
if '.' in i:
suffix = ''
else:
suffix = '/'
links[i] = {'href':
urllib.parse.urljoin(prefix, i) + suffix}
return links
然后在你的序列化器中使用它:
class SomeModelSerializer(serializers.HyperlinkedModelSerializer):
_links = HALNestedLinksField(['revalidate'], # you detail_route names
view_name='somemodel-detail')
class Meta:
model = SomeModel
fields = ('url',
'date',
'_links') # do not forget it
并且您将获得一个 _links
属性,其中包含您在 HALNestedLinksField
中声明的所有相关路由。
我正在尝试通过 @list_route
和 @detail_route
装饰器使用嵌套路由。路线和 return 数据有效,但我必须在地址栏中手动导航到它们。它们不会出现在 DefaultRouter
生成的 ApiRoot
中可浏览 API。我正在使用 Django 1.8 和 Rest Framework 3.1.1。
在urls.py:
router = DefaultRouter()
router.register(r'aggregates', viewsets.AggregateViewSet, base_name='aggregate')
urlpatterns = [
url(r'^api/', include(router.urls, namespace='myapp')),
]
在viewsets.py:
class AggregateViewSet(viewsets.GenericViewSet):
queryset = models.DataAggregate.objects.order_by('id')
serializer_class = serializers.AggregateSerializer
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
@list_route(url_path='recent')
def recent_aggregates(self, request):
return Response({'message': 'herp a derp'})
当我导航到 /myapp/api
时,可浏览的 API 只显示:
HTTP 200 OK
Content-Type: application/json
Vary: Accept
Allow: GET, HEAD, OPTIONS
{
"aggregates": "http://localhost:8000/myapp/api/aggregates/"
}
我期待这个:
{
"aggregates": "http://localhost:8000/myapp/api/aggregates/"
"aggregates-recent": "http://localhost:8000/myapp/api/aggregates/recent"
}
我试过各种修改版本,看能不能让步,都无济于事。同样,如果我手动导航到这些路由 do 函数和可浏览的 API 将显示它们的页面......但是违背了可浏览的目的 api.
我看了一下 DefaultRouter
(和 SimpleRouter
)的代码,它似乎发现了动态路由...
没错,默认情况下它不会出现在 API 中。
我自己使用该代码段来提供遵循 HAL 样式(py3 代码)的嵌套路由。
import urllib
from collections import OrderedDict
from rest_framework import serializers, relations
class SubNamespaceURLField(relations.HyperlinkedIdentityField):
"""Refers to a child namespace of the object, as pointed by view_name
"""
def __init__(self, namespace, *args, **kwargs):
self.namespace = namespace.strip('/')
super().__init__(*args, **kwargs)
def field_to_native(self, obj, field_name):
base = super().field_to_native(obj, field_name)
return urllib.parse.urljoin(base, self.namespace) + '/'
class HALNestedLinksField(relations.HyperlinkedIdentityField):
""" Tries to represent a list of nested links on the resource a
HAL-compliant way.
See http://stateless.co/hal_specification.html
"""
def __init__(self, endpoints, *args, **kwargs):
"""
:param endpoints list of url suffixes leading to nested operations on
the resource (ex: ['preview', 'check'])
"""
self.endpoints = endpoints
super().__init__(*args, **kwargs)
def get_attribute(self, obj):
return obj
def to_representation(self, value):
links = OrderedDict()
prefix = super().to_representation(self.get_attribute(value))
for i in self.endpoints:
# We consider if it contains a dot its a content-type indication,
# so no trailing slash
if '.' in i:
suffix = ''
else:
suffix = '/'
links[i] = {'href':
urllib.parse.urljoin(prefix, i) + suffix}
return links
然后在你的序列化器中使用它:
class SomeModelSerializer(serializers.HyperlinkedModelSerializer):
_links = HALNestedLinksField(['revalidate'], # you detail_route names
view_name='somemodel-detail')
class Meta:
model = SomeModel
fields = ('url',
'date',
'_links') # do not forget it
并且您将获得一个 _links
属性,其中包含您在 HALNestedLinksField
中声明的所有相关路由。