Django rest framework-其他

本文为学习官方文档时所做笔记,可以看做是官方文档的全文翻译

自定义混合类

  • 自定义一个基于多个URL查询参数的创造混合类

    class MultipleFieldLookupMixin(object):
        """
        Apply this mixin to any view or viewset to get multiple field filtering
        based on a `lookup_fields` attribute, instead of the default single field filtering.
        """
        def get_object(self):
            queryset = self.get_queryset()             # Get the base queryset
            queryset = self.filter_queryset(queryset)  # Apply any filter backends
            filter = {}
            for field in self.lookup_fields:
                if self.kwargs[field]: # Ignore empty fields.
                    filter[field] = self.kwargs[field]
            obj = get_object_or_404(queryset, **filter)  # Lookup the object
            self.check_object_permissions(self.request, obj)
            return obj
    

    在需要的视图使用

    class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
        lookup_fields = ['account', 'username']
    

查询是否已登录

  • 通过perform_create

    def perform_create(self, serializer):
        queryset = SignupRequest.objects.filter(user=self.request.user)
        if queryset.exists():
            raise ValidationError('You have already signed up')
        serializer.save(user=self.request.user)
    

增加额外动作

  • @action装饰器

    from django.contrib.auth.models import User
    from rest_framework import status, viewsets
    from rest_framework.decorators import action
    from rest_framework.response import Response
    from myapp.serializers import UserSerializer, PasswordSerializer
    
    class UserViewSet(viewsets.ModelViewSet):
        """
        A viewset that provides the standard actions
        """
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
        @action(detail=True, methods=['post'])
        def set_password(self, request, pk=None):
            user = self.get_object()
            serializer = PasswordSerializer(data=request.data)
            if serializer.is_valid():
                user.set_password(serializer.data['password'])
                user.save()
                return Response({'status': 'password set'})
            else:
                return Response(serializer.errors,
                                status=status.HTTP_400_BAD_REQUEST)
    
        @action(detail=False)
        def recent_users(self, request):
            recent_users = User.objects.all().order_by('-last_login')
    
            page = self.paginate_queryset(recent_users)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(recent_users, many=True)
            return Response(serializer.data)
    

    该装饰器也可以设置

    @action(detail=True, methods=['post','delete'], permission_classes=[IsAdminOrIsSelf])
    

    建立了额外动作之后,将可以在 ^users/{pk}/set_password/$^users/{pk}/unset_password/$ 中访问到。一个视图的所有额外做的可以通过方法.get_extra_actions() 来查询

    通过@action设置的额外动作会自动注册到router中并产生相应的url地址,如上文的set_passwprd

    • URL path: ^users/{pk}/set_password/$,基于basename产生
    • URL name: 'user-set-password'

    如果想自定义这两个值,则需要在装饰器中自定义以下两个值

      @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
                url_path='change-password', url_name='change_password')
    

    产生的效果如下

    • URL path: ^users/{pk}/change-password/$
    • URL name: change_password,完整名在前面加上basename,变为'users-change_password'

反向解析动作的URL

  • .get_extra_actions() :从一个动作名得到其对应的url地址

    //#如果没有设置ViewSet及注册到router中,则需要手动设置basename
    
    >>> view.reverse_action('set-password', args=['1']) 
    'http://localhost:8000/api/users/1/set_password'
    
    >>> view.reverse_action(view.set_password.url_name, args=['1']) #set_password为设置的basename,url_name为@action装饰器中设置的的动作名(如果有)
    'http://localhost:8000/api/users/1/set_password'
    
posted @ 2020-06-06 17:54  言兴  阅读(118)  评论(0)    收藏  举报