我正在使用 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
中添加一个函数 View :
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
而不是像这样编写一次性函数 View 。
有什么想法吗?
最佳答案
我花了一段时间才弄明白这一点。我一直在使用 View 集,所以我会在该设置中给出这个答案。
首先,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
将对应于 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 完成您想要的操作.我还没有尝试过,所以我不能说如何使用它们,但该链接上有很好的示例。
关于python - Django Rest Framework - 添加 JOIN 端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38626017/