如何在不同模型的 ID 下建立动态的 REST API 链接?

2024-09-28 04:47:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前与django rest建立的关系是:

型号名称:动漫

  • /api/<;-根
  • /api/animes/<;-列出my db中可用的所有动画
  • /api/animes/id/<;-返回id=id的动画实例

型号名称:剧集

  • /api/<;-根
  • /api/集/<;-列出我的数据库中所有可用动画的所有片段
  • /api/集/id/<;-返回id=id的事件实例

所以基本上我想实现的是:

如果我请求api/剧集/{anime\u name}/

我把那部动画片的情节列出来了

我该怎么做

情节序列化程序

class EpisodesSerializer(serializers.ModelSerializer):
class Meta:
    model   = Episodes
    fields = '__all__'

路由器

router = routers.DefaultRouter()
router.register('animes', AnimesViewSet, 'animes')
router.register('episodes', EpisodesViewSet, 'episodes')

urlpatterns = router.urls

场景视图集

class EpisodesViewSet(viewsets.ModelViewSet):

   permission_classes  = [permissions.AllowAny]
   MainModel           = Episodes
   queryset            = Episodes.objects.all()
   serializer_class    = EpisodesSerializer

Tags: 实例lt名称apiid动画allclass
1条回答
网友
1楼 · 发布于 2024-09-28 04:47:34

编辑

正如评论中提到的,DRF的较新版本使用@action,因为@detail\u route和@list\u route已被弃用

要使用不同的字段进行查找,可以自己实现获取对象的逻辑,但必须确保用于查找的字段是唯一的,否则可以返回许多对象

因此,假设动画name是唯一的,并且您希望使用它进行查找,您可以这样做:

@action(detail=True, methods=['get'])
def episodes(self, *args, **kwargs):
    anime = Anime.objects.get(name=self.kwarg[self.lookup_field])
    episodes = Episode.objects.filter(anime=anime)
    ...

您还可以检查get_object()是如何实现的,以使其更加健壮。 我为自己创建了一个通用视图mixin,它允许从主pk lookup字段使用多个唯一字段aprt进行查找:

class AlternateLookupFieldsMixin(object):
"""
Looks up objects for detail endpoints using alternate
lookup fields assigned in `alternate_lookup_fields` apart
from the default lookup_field. Only unique fields should be used
else Http404 is raised if multiple objects are found
"""

alternate_lookup_fields = []

def get_object(self):
    try:
        return super().get_object()
    except Http404:
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
        queryset = self.filter_queryset(self.get_queryset())
        obj = None
        for lookup_field in self.alternate_lookup_fields:
            filter_kwargs = {lookup_field: self.kwargs[lookup_url_kwarg]}
            try:
                obj = get_object_or_404(queryset, **filter_kwargs)
            except Http404:
                pass
        if obj:
            self.check_object_permissions(self.request, obj)
            return obj
        raise Http404

您所要做的就是将它添加到视图的基类中,并在alternate_lookup_fields属性中添加用于查找的字段(在您的例子中是名称)。当然,只能使用唯一字段

至于过滤,您可以检查过滤的简单程度here。 但是,我建议使用更通用的过滤器后端,如django-filter


原始答案

首先,url看起来更具初始化性,如下所示:

api/anime/<anime_id>/episodes/

这是因为您通常应该从一个更通用的资源到更具体的资源

为了实现这一点,在AnimeViewSet(而不是eposodesviewset)中,您可以有这样一个情节的详细路线:

from rest_framework.decorators import detail_route


@detail_route(methods=['get'])
def episodes(self, *args, **kwargs):
    anime = self.get_object()
    episodes = Episode.objects.filter(anime=anime)
    page = self.paginate_queryset(anime)
    if page is not None:
        serialier = EpisodesSerializer(page, context=self.get_serializer_context(), many=True)
        return self.get_paginated_response(serializer.data)

    serializer = EpisodesSerializer(episodes, context=self.get_serializer_context()) many=True)
    return Response(serializer.data)

您也可以使用eposodesviewset上的过滤器以这种方式获取属于特定动画的片段:

api/episodes?anime=<anime_id>

相关问题 更多 >

    热门问题