2016-07-28 2 views
3

Я делаю REST API с Джанго Rest Framework (ФПИ), который имеет следующие конечные точки:Django Framework Rest - добавление РЕГИСТРИРУЙТЕСЬ конечные точки

/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',) 

Есть хороший способ, чтобы добавить эту конечную точку в ФПИ, учитывая то, как я использую ФПИ?

Я мог бы просто добавить представление функции в 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 с вместо кодирования Разового вида функции, как это.

Любые идеи?

ответ

1

Пришло время понять это. Я использую наборы представлений, поэтому я дам этот ответ в этой настройке.

Во-первых, привязок и зарегистрированные маршруты остаются неизменными, то есть,

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. Я не пробовал (пока), поэтому я не могу сказать, как их использовать, но есть хорошие примеры по этой ссылке.

Смежные вопросы