我试图通过@list_route
和@detail_route
装饰器使用嵌套路由。路由工作并返回数据,但我必须在地址栏中手动导航到它们。它们不会出现在可浏览API中DefaultRouter
生成的ApiRoot
中。我正在使用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"
}
我尝试了各种修改版本,看看它是否会让步,无济于事。同样,这些路线做功能,如果我手动导航它们,可浏览的API将显示它们的页面......但是会破坏可浏览api的目的。
我看了DefaultRouter
(和SimpleRouter
)的代码,它似乎确实发现了动态路线......
答案 0 :(得分:2)
这是真的,并且默认情况下它不会出现在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
中声明的所有相关路线。