我正在使用具有以下端点的Django Rest Framework(DRF)制作REST API:
/users/
/users/<pk>/
/items/
/items/<pk>/
但我想添加端点:
/users/<pk>/items/
当然会将属于(拥有外键)的项目返回给该用户。
目前我的代码是:
#########################
##### myapp/urls.py #####
#########################
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from rest_framework.decorators import api_view, renderer_classes
from rest_framework import response, schemas
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer
from myapp.views import ItemViewSet, UserViewSet
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'items', ItemViewSet)
@api_view()
@renderer_classes([OpenAPIRenderer, SwaggerUIRenderer])
def schema_view(request):
generator = schemas.SchemaGenerator(title='My API')
return response.Response(generator.get_schema(request=request))
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
##########################
##### myapp/views.py #####
##########################
from django.contrib.auth import get_user_model
from rest_framework import viewsets, permissions
from myapp.serializers import MyUserSerializer, ItemSerializer
from myapp.models import Item
class UserViewSet(viewsets.ReadOnlyModelViewSet):
queryset = get_user_model().objects.all()
serializer_class = MyUserSerializer
permission_classes = (permissions.IsAuthenticated,)
class ItemViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
permission_classes = (permissions.IsAuthenticated,)
################################
##### myapp/serializers.py #####
################################
from rest_framework import serializers
from django.contrib.auth import get_user_model
from myapp.models import Item
class MyUserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('pk', 'email',)
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('pk', 'name',)
考虑到我如何使用DRF,有没有一种方法可以在DRF中添加此端点?
我可以在urls.py
中添加一个功能视图,如下所示:
from myapp.views import items_for_user
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^users/(?P<pk>[0-9]+)/items/$', items_for_user),
]
但我想利用DRF,获取可浏览的API,并使用ViewSet
而不是像这样编写一次性函数视图。
有什么想法吗?
答案 0 :(得分:1)
我花了一些时间来弄明白这一点。我一直在使用视图集,所以我会在这个设置中给出这个答案。
首先,URLConf和注册路线保持不变,即
router = DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'items', ItemViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/',
include('rest_framework.urls', namespace='rest_framework')
),
]
您的商品仍然位于/items/<pk>/
,具有为每个商家设置的权限,具体取决于他们是谁,通过创建自定义权限,例如:
class IsItemOwnerPermissions(permissions.DjangoObjectPermissions):
"""
The current user is the owner of the item.
"""
def has_object_permission(self, request, view, obj):
# A superuser?
if request.user.is_superuser:
return True
# Owner
if obj.owner.pk == request.user.pk:
return True
return False
接下来,对于/user/<pk>/items/
,您需要定义@detail_route
,如下所示:
class UserViewSet(viewsets.ReadOnlyModelViewSet):
# Your view set properties and methods
@detail_route(
methods=['GET', 'POST'],
permission_classes=[IsItemOwnerPermissions],
)
def items(self, request, pk=None):
"""
Returns a list of all the items belonging to `/user/<pk>`.
"""
user = get_user_model().objects.get(pk=pk)
items = user.items.all()
page = self.paginate_queryset(items)
if page is None:
serializer = ItemSerializer(
objs, context={'request': request}, many=True
)
return Response(serializer.data)
else:
serializer = ItemSerializer(
page, context={'request': request}, many=True
)
return self.get_paginated_response(serializer.data)
名为xyz
的详细路线对应于路线user/<pk>/xyz
。还有列表路线(@list_route
);名为xyz
的{{1}}对应user/xyz
(例如user/add_item
)。
以上结构将为您提供:/user
,/user/<pk>
,user/<pk>/items
,/items
和/items/<pk>
,但不 (正如我错误地试图实现的那样)user/<user_pk>/items/<items_pk>
。相反,user/<pk>/items
会为您提供用户列表,但只能通过/items/<pk>
访问其各自的属性。
我刚刚将这个用于我的项目,上面的代码可以快速适应您的情况。我希望它对你有帮助,但那里可能还有问题。
更新:您可以使用custom hyperlinked fields完成所需操作。我还没有尝试过,所以我不能说如何使用它们,但是在这个链接上有很好的例子。