我如何制作一个模型的动态REST API链接,该链接会因另一个模型的ID而改变?

时间:2019-09-10 14:11:33

标签: python django django-rest-framework

我目前使用django rest设置的是:

模型名称:动漫

  • / api / <-根
  • / api / animes / <-列出数据库中所有可用的动漫
  • / api / animes / id / <-返回具有id = id的动漫实例

模型名称:剧集

  • / api / <-根
  • / api / episodes / <-列出数据库中所有可用动漫的所有情节
  • / api / episodes / id / <-返回具有id = id的情节实例

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

如果我请求 api / episodes / {anime_name} /

我列出了特定动漫的情节。

我该怎么做?

EpisodesSerializer

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

EpisodesViewSet

class EpisodesViewSet(viewsets.ModelViewSet):

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

1 个答案:

答案 0 :(得分:1)

编辑

正如评论中提到的OP一样,DRF的较新版本使用@action代替,因为不推荐使用@detail_route和@list_route。

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

因此,假设动漫@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()

您还可以检查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 的实现方式,使其更强大。     我为自己制作了一个通用的视图mixin,它允许从主pk查找字段中的多个唯一字段进行查找:

alternate_lookup_fields

所有您需要做的就是将其添加到视图的基类中,并在api/anime/<anime_id>/episodes/ 属性中添加用于lookup(根据情况命名)的字段。当然,只能使用唯一字段。

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


原始答案

首先,URL看起来像这样更具创意:

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)

这是因为您通常应该从更通用的资源开始,到更具体的资源。

要实现此目的,请在您的AnimeViewSet(而不是EpisodesViewSet)中,为这些情节提供详细的路线:

api/episodes?anime=<anime_id>

您还可以仅使用EpisodesViewSet上的过滤器以这种方式获取属于特定动漫的剧集:

$('#AdvertsListe').initDataTables(routes.datatable_settings, {
        "dom": "Blfrtip",
        'searching' : true,
       "bFilter": true,
        'ordering' : true,
        "columnDefs": [
            {
                "targets": 0,
                "width": "8%"
            },
            {
                "targets": 0,
                "width": "8%"
            }

        ]
    }).then(function(dt) {
        // dt contains the initialized instance of DataTables
        dt.on('init', function() {
            $('.column_filter').on('change', function (e) {
                let index = $(this).data('column');
                let searchStr = $(this).val();
                if ($(this).val() != ''){
                    dt.column(index).search(searchStr).draw();
                }

                e.stopPropagation();
                return false;
            });
        })
    });