Django - DRF - 뷰 최적화 어셈블리

20424 단어 DjangoDRF
카탈로그
1. 데이터베이스의 삭제와 수정을 실현한다. - 일반적인 쓰기가 최적화되지 않았다(두 개의 루트와 두 개의 보기)
1-1 두 라우팅 배포 - 연결 또는 연결 안 함
데이터 검색을 위한 1-2 Serializers
1-3 뷰 함수
2. 최적화 방식 1 - Generic APIView, List Model Mixin, Create Model Mixin...
2-1 보기 함수 + 루트 설계
2-2 보기 최적화 사고방식 - 단독 중복 코드 제시, 분류 및 방법 봉인
2-3 소스 분석
2-3-1 GenericAPIView - 뷰 최적화 베이스 클래스
2-3-2 ListModelMixin - get 데이터 목록 가져오기
2-3-3 CreateModelMixin - 객체 만들기
2-3-4 RetrieveModelMixin - 단일 객체 가져오기
2-3-5 UpdateModelMixin - 개별 객체 업데이트
2-3-6 DestroyModelMixin - 객체 삭제
3. 방식 2 - ListCreate APIView, RetrieveUpdate Destroy APIView
3-1 뷰 함수
3-2 소스 분석
3-2-1 ListCreateAPIView
3-2-2 RetrieveUpdateDestroyAPIView 
3-2-3  RetrieveDestroyAPIView
3-2-4 RetrieveUpdateAPIView
4, 방식 3 - ModelViewSet 협조urls 루트(추천하지 않음)
4-1 라우팅 설계
4-2 뷰 함수
4-3 원본 코드 분석
1. 데이터베이스의 삭제와 수정을 실현한다. - 일반적인 쓰기가 최적화되지 않았다(두 개의 루트와 두 개의 보기)
1-1 두 라우팅 배포 - 연결 또는 연결 안 함
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^publish/$', views.PublishView.as_view()),
    url(r'^publish/(?P\d+)', views.PublishDetailView.as_view()),
]

데이터 검색을 위한 1-2 Serializers
from rest_framework import serializers
from app01 import models

class PublishSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = '__all__'

1-3 뷰 함수
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from django.http import JsonResponse
from app01 import MySerializer

class PublishView(APIView):
    def get(self, request):
        publish_list = models.Publish.objects.all()
        ser = MySerializer.PublishSerializers(publish_list, many=True)
        return JsonResponse(ser.data, safe=False)

    def post(self, request):
        ser = MySerializer.PublishSerializers(data=request.data)
        if ser.is_valid():
            ser.save()
            return JsonResponse(ser.data, safe=False)
        else:
            return JsonResponse(ser.errors, safe=False)


class PublishDetailView(APIView):
    def get(self, request, pk):
        publish_obj = models.Publish.objects.filter(pk=pk).first()
        ser = MySerializer.PublishSerializers(publish_obj, many=False)
        return JsonResponse(ser.data, safe=False)

    def put(self, request, pk):
        publish_obj = models.Publish.objects.filter(pk=pk).first()
        ser = MySerializer.PublishSerializers(data=request.data, instance=publish_obj)
        if ser.is_valid():
            ser.save()
            return JsonResponse(ser.data, safe=False)
        else:
            return JsonResponse(ser.errors, safe=False)

    def delete(self, request, pk):
        models.Publish.objects.filter(pk=pk).delete()
        return JsonResponse("delete", safe=False)

2. 최적화 방식 1 - Generic APIView, List Model Mixin, Create Model Mixin...
요약:
  • ListModelMixin - 객체 목록 가져오기
  • CreateModelMixin - 객체 데이터 생성
  • RetrieveModelMixin - 지정된 객체 데이터 가져오기
  • UpdateModelMixin - 객체 데이터 업데이트
  • DestroyModelMixin - 객체 데이터 삭제
  • 2-1 보기 함수 + 루트 설계
    '''
    from django.conf.urls import url,include
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publish/$', views.PublishView.as_view()),
        url(r'^publish/(?P\d+)', views.PublishDetailView.as_view()),
    ]
    
    '''
    
    from app01 import models
    from app01 import MySerializer
    from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
        DestroyModelMixin
    
    from rest_framework.generics import GenericAPIView
    
    
    class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin):
        queryset = models.Publish.objects.all()
        serializer_class = MySerializer.PublishSerializers
    
        def get(self, request):
            return self.list(request)
    
        def post(self, request):
            return self.create(request)
    
    
    class PublishDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
        queryset = models.Publish.objects.all()
        serializer_class = MySerializer.PublishSerializers
    
        def get(self, request, pk):
            return self.retrieve(request, pk)
    
        def put(self, request, pk):
            return self.update(request, pk)
    
        def delete(self, request, pk):
            return self.destroy(request, pk)

    2-2 보기 최적화 사고방식 - 단독 중복 코드 제시, 분류 및 방법 봉인
    '''
    from django.conf.urls import url,include
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publish/$', views.PublishView.as_view()),
        url(r'^publish/(?P\d+)', views.PublishDetailView.as_view()),
    ]
    
    '''
    
    '''
              ,       ,       
    '''
    class List:
        def list(self, request):
            # queryset : Publish.objects.all(),serializers : PublishSerializers
            queryset = self.queryset.all()
            ser = self.serializers(queryset, many=True)
            return JsonResponse(ser.data, safe=False)
    
    
    class Create:
        def create(self, request):
            print(request.data)
    
            ser = MySerializer.PublishSerializers(data=request.data)
            if ser.is_valid():
                ser.save()  #     
                return JsonResponse(ser.data, safe=False)
            else:
    
                return JsonResponse(ser.errors, safe=False)
    
    
    class Retrieve:
        def retrieve(self, request, pk):
            queryset = self.queryset.all()
            obj = queryset.filter(pk=pk).first()
            ser = self.serializers(obj, many=False)
            return JsonResponse(ser.data, safe=False)
    
    
    class Update:
        def update(self, request, pk):
            obj = self.queryset.filter(pk=pk).first()
            ser = self.serializers(data=request.data, instance=obj, many=False)
            if ser.is_valid():
                ser.save()
                return JsonResponse(ser.data, safe=False)
            else:
                return JsonResponse(ser.errors, safe=False)
    
    
    class Destroy:
        def destroy(self, request, pk):
            self.queryset.filter(pk=pk).delete()
            return JsonResponse("delete", safe=False)
    
    
    class PublishView(APIView, List, Create):
        queryset = models.Publish.objects.all()
        serializers = MySerializer.PublishSerializers
    
        def get(self, request):
            return self.list(request)
    
        def post(self, request):
            #       
            return self.create(request)
    
    
    class PublishDetailView(APIView, Retrieve, Update, Destroy):
        queryset = models.Publish.objects.all()
        serializers = MySerializer.PublishSerializers
    
        def get(self, request, pk):
            return self.retrieve(request, pk)
    
        def put(self, request, pk):
            return self.update(request, pk)
    
        def delete(self, request, pk):
            return self.destroy(request, pk)
    

    2-3 소스 분석
    2-3-1 GenericAPIView - 뷰 최적화 베이스 클래스
    class GenericAPIView(views.APIView):
        """
        Base class for all other generic views.
        """
        # You'll need to either set these attributes,
        # or override `get_queryset()`/`get_serializer_class()`.
        # If you are overriding a view method, it is important that you call
        # `get_queryset()` instead of accessing the `queryset` property directly,
        # as `queryset` will get evaluated only once, and those results are cached
        # for all subsequent requests.
        '''
                 ,    ' get_queryset() ' / ' get_serializer_class() '。
                ,       ' get_queryset() '       ' queryset '  ,
      ‘queryset’       ,                 。
        '''
        queryset = None
        serializer_class = None
    
        # If you want to use object lookups other than pk, set 'lookup_field'.
        # For more complex lookup requirements override `get_object()`.
        '''
              pk       ,   “lookup_field”。
                  ,   ' get_object() '。
        '''
        lookup_field = 'pk'
        lookup_url_kwarg = None
    
        # The filter backend classes to use for queryset filtering
        #   queryset        
        filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    
        # The style to use for queryset pagination.
        #   queryset     。
        pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    
        def get_queryset(self):
            """
            Get the list of items for this view.
            This must be an iterable, and may be a queryset.
            Defaults to using `self.queryset`.
    
            This method should always be used rather than accessing `self.queryset`
            directly, as `self.queryset` gets evaluated only once, and those results
            are cached for all subsequent requests.
    
            You may want to override this if you need to provide different
            querysets depending on the incoming request.
    
            (Eg. return a list of items that is specific to the user)
            """
            assert self.queryset is not None, (
                "'%s' should either include a `queryset` attribute, "
                "or override the `get_queryset()` method."
                % self.__class__.__name__
            )
    
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                # Ensure queryset is re-evaluated on each request.
                queryset = queryset.all()
            return queryset
    
        def get_object(self):
            """
            Returns the object the view is displaying.
    
            You may want to override this if you need to provide non-standard
            queryset lookups.  Eg if objects are referenced using multiple
            keyword arguments in the url conf.
            """
            queryset = self.filter_queryset(self.get_queryset())
    
            # Perform the lookup filtering.
            lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
    
            assert lookup_url_kwarg in self.kwargs, (
                'Expected view %s to be called with a URL keyword argument '
                'named "%s". Fix your URL conf, or set the `.lookup_field` '
                'attribute on the view correctly.' %
                (self.__class__.__name__, lookup_url_kwarg)
            )
    
            filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
            obj = get_object_or_404(queryset, **filter_kwargs)
    
            # May raise a permission denied
            self.check_object_permissions(self.request, obj)
    
            return obj
    
        def get_serializer(self, *args, **kwargs):
            """
            Return the serializer instance that should be used for validating and
            deserializing input, and for serializing output.
            """
            serializer_class = self.get_serializer_class()
            kwargs['context'] = self.get_serializer_context()
            return serializer_class(*args, **kwargs)
    
        def filter_queryset(self, queryset):
            """
            Given a queryset, filter it with whichever filter backend is in use.
    
            You are unlikely to want to override this method, although you may need
            to call it either from a list view, or from a custom `get_object`
            method if you want to apply the configured filtering backend to the
            default queryset.
                queryset,              。
                         ,                  “get_object”   ,
                                。  queryset。
            """
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset

    2-3-2 ListModelMixin - get 데이터 목록 가져오기
    class ListModelMixin(object):
        """
        List a queryset.
        """
        def list(self, request, *args, **kwargs):
            # GenericAPIView  filter_queryset get_queryset
            #                 queryset
            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)
            # GenericAPIView  get_serializer
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

    2-3-3 CreateModelMixin - 객체 만들기
    class CreateModelMixin(object):
        """
        Create a model instance.
        """
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            #     perform_create
            self.perform_create(serializer)
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
        #     
        def perform_create(self, serializer):
            serializer.save()
    
        def get_success_headers(self, data):
            try:
                return {'Location': str(data[api_settings.URL_FIELD_NAME])}
            except (TypeError, KeyError):
                return {}

    2-3-4 RetrieveModelMixin - 단일 객체 가져오기
    class RetrieveModelMixin(object):
        """
        Retrieve a model instance.
        """
        def retrieve(self, request, *args, **kwargs):
            # GenericAPIView get_object  ,      
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
    
    
    
    def get_object_or_404(queryset, *filter_args, **filter_kwargs):
        """
        Same as Django's standard shortcut, but make sure to also raise 404
        if the filter_kwargs don't match the required types.
        """
        try:
            return _get_object_or_404(queryset, *filter_args, **filter_kwargs)
        except (TypeError, ValueError, ValidationError):
            raise Http404

    2-3-5 UpdateModelMixin - 개별 객체 업데이트
    class UpdateModelMixin(object):
        """
        Update a model instance.
        """
        def update(self, request, *args, **kwargs):
            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)
    
            if getattr(instance, '_prefetched_objects_cache', None):
                # If 'prefetch_related' has been applied to a queryset, we need to
                # forcibly invalidate the prefetch cache on the instance.
                instance._prefetched_objects_cache = {}
    
            return Response(serializer.data)
    
        def perform_update(self, serializer):
            serializer.save()
    
        def partial_update(self, request, *args, **kwargs):
            kwargs['partial'] = True
            return self.update(request, *args, **kwargs)

    2-3-6 DestroyModelMixin - 객체 삭제
    class DestroyModelMixin(object):
        """
        Destroy a model instance.
        """
        def destroy(self, request, *args, **kwargs):
            instance = self.get_object()
            self.perform_destroy(instance)
            return Response(status=status.HTTP_204_NO_CONTENT)
    
        def perform_destroy(self, instance):
            instance.delete()
    

    3. 방식 2 - ListCreate APIView, RetrieveUpdate Destroy APIView
    ListCreate APIView - Generic APIView, ListModel Mixin, Create Model Mixin과 동일
    Retrieve Update Destroy APIView -Generic APIView, Retrieve Model Mixin, Update Model Mixin, Destroy Model Mixin과 동일
    3-1 뷰 함수
    from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
    from app01 import MySerializer
    from app01 import models
    
    #    class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin):
    class PublishView(ListCreateAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = MySerializer.PublishSerializers
    
    
    class PublishDetailView(RetrieveUpdateDestroyAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = MySerializer.PublishSerializers
    

    3-2 소스 분석
    3-2-1 ListCreateAPIView
    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)

    3-2-2 RetrieveUpdateDestroyAPIView 
    class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
                                       mixins.UpdateModelMixin,
                                       mixins.DestroyModelMixin,
                                       GenericAPIView):
        """
        Concrete view for retrieving, updating or deleting a model instance.
        """
        def get(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return self.update(request, *args, **kwargs)
    
        def patch(self, request, *args, **kwargs):
            return self.partial_update(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return self.destroy(request, *args, **kwargs)
    

    3-2-3  RetrieveDestroyAPIView
    class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,
                                 mixins.DestroyModelMixin,
                                 GenericAPIView):
        """
        Concrete view for retrieving or deleting a model instance.
        """
        def get(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return self.destroy(request, *args, **kwargs)
    

    3-2-4 RetrieveUpdateAPIView
    class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
                                mixins.UpdateModelMixin,
                                GenericAPIView):
        """
        Concrete view for retrieving, updating a model instance.
        """
        def get(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return self.update(request, *args, **kwargs)
    
        def patch(self, request, *args, **kwargs):
            return self.partial_update(request, *args, **kwargs)
    

     
    4, 방식 3 - ModelViewSet 협조urls 루트(추천하지 않음)
    4-1 라우팅 설계
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        #   ViewSetMixin,  as_view    
        url(r'^publish/$', views.PublishView.as_view({'get': 'list', 'post': 'create'})),
        url(r'^publish/(?P\d+)', views.PublishView.as_view({'get': 'retrieve', 'put': 'update','delete':'destroy'})),
    
    ]
    

    4-2 뷰 함수
    from rest_framework.viewsets import ModelViewSet
    
    
    # ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
    #              mixins.DestroyModelMixin,
    #              mixins.ListModelMixin,
    #              GenericViewSet):
    class PublishView(ModelViewSet):
        queryset = models.Publish.objects.all()
        serializer_class = MySerializer.PublishSerializers
    

    4-3 원본 코드 분석
    class ModelViewSet(mixins.CreateModelMixin,
                       mixins.RetrieveModelMixin,
                       mixins.UpdateModelMixin,
                       mixins.DestroyModelMixin,
                       mixins.ListModelMixin,
                       GenericViewSet):
        """
        A viewset that provides default `create()`, `retrieve()`, `update()`,
        `partial_update()`, `destroy()` and `list()` actions.
        """
        pass
    

    좋은 웹페이지 즐겨찾기