python - Django Rest Framework - 添加 JOIN 端点

标签 python django rest

我正在使用 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/

相关文章:

java - 要使用 REST API 需要实现什么设计模式?

rest - SOAPUI 错误 : Attempted read from closed stream for JSON POST to redirect to GET after 302

python - numpy 数组上的简单多处理

python - 在 scrapy 中提取带有其他文本数据的嵌套标签作为字符串

python - 我可以使用 pywikipedia 来获取页面的文本吗?

django - 在全局范围内将所有页面设置为需要登录?

Python - 如何删除超过 1 个空格

python - 模板 password_reset_form.html 不会覆盖 django 管理模板

python - Travis CI 与 mysql 和 django 返回 (1045, "Access denied for user ' root' @'localhost' (使用密码 : YES)")

java - 如何在 Spring Controller 中请求请求的来源和主体