Get object by field other than primary key

前端 未结 5 1012
眼角桃花
眼角桃花 2020-12-30 09:52

Hi I\'m new to both Django and the Django-Rest-Framework. I\'ve gone through the tutorials. What I\'m trying to do (as a learning exercise) is return an object based off a f

相关标签:
5条回答
  • 2020-12-30 10:04

    Using ModelViewSets you can use @action decorator you can define specific method if you don't want to change the complete lookup behavior of the viewset and serializer. For example:

    class VideoDetailView(viewsets.ModelViewSet):
        queryset = Videos.objects.all()
        serializer_class = VideosSerializer
    
        @action(detail=True)
        def video_name(self, request, pk=None):
            queryset = Video.objects.get(videoName=pk) # pk will be the video name
            serializer = VideosSerializer(queryset, many=True) # You can specify other serializer if you want here
            return Response(serializer.data)
    

    Then, your url will be: myserver:8000/videos/SecondVideo/video_name/

    You can read more in: https://www.django-rest-framework.org/api-guide/viewsets/

    0 讨论(0)
  • 2020-12-30 10:07

    Credit https://www.youtube.com/watch?v=dWZB_F32BDg

    Use lookup_field to define the field used for querying the table and look_up_kwargs for the field in the url

    url(r'^videos/(?P<videoName>[^/]+)/$', video_detail)

    class VideoDetailView(viewsets.ModelViewSet):
        serializer_class = VideosSerializer
        queryset = Videos.objects.all()
        lookup_field = 'videoName'
        lookup_url_kwarg = 'videoName'
    
    0 讨论(0)
  • 2020-12-30 10:13

    Try setting the lookup_field attribute on your view class. That is the field that will be used to look up an individual model instance. It defaults to 'pk' but you can change it to 'videoName'.

    class VideoDetailView(viewsets.ModelViewSet):
        serializer_class = VideosSerializer
        lookup_field = 'videoName'
    
    0 讨论(0)
  • 2020-12-30 10:17

    So I figured it out. What was going on was the

    router.register(r'videos', views.VideosViewSet)
    

    Was handling myserver:8000/videos/1 and so my a new url pattern url(r'^videos/(?P<videoName>.+)/$', views.VideoDetailView.as_view()) was being overridden by the registered route. The code that works is:

    urls.py
    
    url(r'^video/(?P<videoName>.+)/$', views.VideoDetailView.as_view())
    
    views.py
    
    class VideoDetailView(generics.ListAPIView):
        serializer_class = VideosSerializer
    
        def get_queryset(self):
            videoName = self.kwargs['videoName']
            return Videos.objects.filter(videoName=videoName)
    

    This documentation page on filtering against the URL helped me piece together what was going on.

    0 讨论(0)
  • 2020-12-30 10:24

    What about a solution just like this:

    views.py

    class VideoDetailView(generics.RetrieveAPIView):
        serializer_class = VideosSerializer
        lookup_field = 'videoName'
    

    reasoning: you want a detailview, so there is no need for ListView but RetriveAPIView

    if some furthere manipulation will be needed just override get_object method like this:

    def get_object(self):
        obj = super(VideoDetailView, self).get_object()
        # perform some extra checks on obj, e.g custom permissions
        return obj
    
    0 讨论(0)
提交回复
热议问题