Django REST framework的各類技巧——4.Generic View

generic view是django神奇的地方,而restframework遵循了這個powerful的機制python

Django REST framework的各類技巧【目錄索引】django

寫在上面

全部的代碼都是在下面的兩個版原本作的segmentfault

django==1.8.8
djangorestframework==3.2.5

一個以前的blog,解釋django generic view
Django generics view 以及看源碼爲何這麼重要api

一組標準的api的實現實現

例若有一個課程類的api,支持增刪改查python2.7

urlpost

url(r'^courses/$', CoursesView.as_view(), name='course-list'),
    url(r'^course/(?P<pk>\d+)/$', CourseDetailView.as_view(), name='course-detail'),

viewui

class CoursesView(ListCreateAPIView):

    filter_backends = (SchoolPermissionFilterBackend, filters.DjangoFilterBackend, filters.SearchFilter)
    permission_classes = (IsAuthenticated, ModulePermission)
    queryset = Course.objects.filter(is_active=True).order_by('-id')
    filter_fields = ('term',)
    search_fields = ('name', 'teacher', 'school__name')
    module_perms = ['course.course']

    def get_serializer_class(self):
        if self.request.method in SAFE_METHODS:
            return CourseFullMessageSerializer
        else:
            return CourseSerializer

    def get_queryset(self):
        return Course.objects.select_related('school', ).filter(
                is_active=True, school__is_active=True, term__is_active=True).order_by('-id')

    @POST('school', validators='required')
    def create(self, request, school, *args, **kwargs):
        if not SchoolPermissionFilterBackend().has_school_permission(request.user, school):
            raise Error(errors.PermissionDenied, err_message=u'沒有對應學校的權限', message=u'沒有對應學校的權限')
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(CourseFullMessageSerializer(serializer.instance).data, status=status.HTTP_201_CREATED, headers=headers


class CourseDetailView(UnActiveModelMixin, DeleteForeignObjectRelModelMixin, RetrieveUpdateDestroyAPIView):

    filter_backends = [SchoolPermissionFilterBackend,]
    serializer_class = CourseSerializer
    permission_classes = (IsAuthenticated, ModulePermission)
    queryset = Course.objects.filter(is_active=True).order_by('-id')
    module_perms = ['course.course']

    def get_serializer_class(self):
        if self.request.method in SAFE_METHODS:
            return CourseFullMessageSerializer
        else:
            return CourseSerializer        
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        school = instance.school
        if not SchoolPermissionFilterBackend().has_school_permission(request.user, school):
            raise Error(errors.PermissionDenied, err_message=u'沒有對應學校的權限', message=u'沒有對應學校的權限')
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    @POST('school', validators='required')
    def update(self, request, school, *args, **kwargs):
        if not SchoolPermissionFilterBackend().has_school_permission(request.user, school):
            raise Error(errors.PermissionDenied, err_message=u'沒有對應學校的權限', message=u'沒有對應學校的權限')
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        return Response(CourseFullMessageSerializer(serializer.instance).data)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        school = instance.school
        if not SchoolPermissionFilterBackend().has_school_permission(request.user, school):
            raise Error(errors.PermissionDenied, err_message=u'沒有對應學校的權限', message=u'沒有對應學校的權限')
        return super(CourseDetailView, self).destroy(request, *args, **kwargs)

怎麼知道重寫什麼方法?

能夠看到我根據需求重寫了一些方法,那麼到底應該重寫那些方法呢?
cd 你的virtualevn/local/lib/python2.7/site-packages/rest_framework
請看下面兩個文件
generics.py
mixins.pyurl

根據繼承關係能夠先看下ListCreateAPIView,能夠看到他提供了get post兩個方法,你固然能夠直接重寫這兩個方法,然而就不能用他不少內置的東東,因此重寫這裏並很差,而應該看他對應的mixinrest

class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
    """ 
    Concrete view for listing a queryset or creating a model instance.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

咱們已get爲例,get中return self.list(request, args, *kwargs),而這個東東是mixins.ListModelMixin裏面的方法code

class ListModelMixin(object):
    """ 
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

因此在這裏你就知道爲嘛restframework在class上要定義一個queryset或者實現get_queryset方法(請繼續看generic view的代碼部分,我不貼了),爲嘛class上定義一個filter_backends能夠實現繼續的filter

其餘的各類mixin各位同窗本身看代碼就知道了,觸類旁通我再也不贅述。

相關文章
相關標籤/搜索