Django restframework 视图

restframework 与原生django一样,有通用视图类APIView, 也实现了通用列表视图函数:ListAPIView(与之类似的还有RetrieveAPIView, UpdateAPIView,DestoryAPIVIew),以及GenericAPIView, ListModelMixin,

首先来看下APIView使用:APIView继承View这个类,所以所有功能都需要自己实现比如get, post,put, patch方法都得自己实现:

View这个基类以及APIView中都没有实现get,post, patch, put这些方法,

而是在dispatch中通过反射来调用这些方法:

def dispatch(self, request, *args, **kwargs):
    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

第一种 APIView

APIView中的dispatch: 不同的是APIView中对request进行了一些封装,并且做了版本,认证,权限,节流的工作:

def dispatch(self, request, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers  # deprecate?
    try:
        self.initial(request, *args, **kwargs)
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(),
                              self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        response = handler(request, *args, **kwargs)
    except Exception as exc:
        response = self.handle_exception(exc)
    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

所以,当继承APIView的视图类需要自己实现所有方法:类似下面这样:

class ArticleView(APIView):
    authentication_classes = []

    def get(self, request, *args, **kwargs):
        article_id = self.request.query_params.get('id')
        if article_id:
            queryset = Article.objects.filter(id=article_id).first()
            ser = FullArticleSerializer(instance=queryset, many=False)
            return Response(ser.data)
        queryset = Article.objects.all()
        ser = FullArticleSerializer(instance=queryset, many=True)
        return Response(ser.data)

    def post(self, request, *args, **kwargs):
        pass

    def put(self, request, *args, **kwargs):
        pass

 

第二种 ListAPIView

而更高一级的ListAPIView则实现了get方法,并且调用了父类ListModelMixin中的list方法

class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

所以当需要获取列表时,并不需要自己实现get方法,除非需要做某些定制:

class ArticleView(ListAPIView):
    queryset = Article.objects.all()

这种情况下,获取列表或者获取详情时都是get方法,所以需要写两个视图类配置不同的url,用来区分get.

 

第三种GenericViewSet 

而更高级的GenericViewSet, ListModelMixin中实现了list方法,对序列化,分页都做了定制,但它并没有实现什么方法,只有一个list方法,被上面的ListAPIView继承,但需要在as_view中指定对应关系。

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass

它继承了ViewSetMixin, generics.GenericAPIView

其中ViewSetMixin重写了as_view方法:所以在url中需要指定请求的方法对应的处理方法,所以只需要一个视图类即可处理所有请求方法。

url(r'^article/$',article.ArticleView.as_view({"get":'list','post':'create'})),
    url(r'^article/(?P<pk>\d+)/$',article.ArticleView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'}))

需要哪个功能,就指定请求方法对应的处理方法,当需要列表时:{'get':'list'}, 而如果需要详情时则是{‘get':'retrieve'}

class ListModelMixin:

    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)

 

通常情况下我们更多的使用ListAPIView, 这些,只需要极少的代码就可以实现功能:如下面这样

serializer

class PageArticleSerializer(serializers.ModelSerializer):
    category = serializers.CharField(source='category.name')
    tag = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = "__all__"

    def get_tag(self, obj):
        return obj.tag.values('id', 'title')

在views中只需要极少的代码即可:

from rest_framework.generics import ListAPIView

class ArticleListView(ListAPIView):
    queryset = Article.objects.all()
    serializer_class = PageArticleSerializer
url(r'^article/list/$', ArticleListView.as_view(), name='list_article'),

127.0.0.1:8000/article/list/

返回结果:

{
    "count": 4,
    "next": "http://127.0.0.1:8000/article/list/?page=2",
    "previous": null,
    "results": [
        {
            "id": 1,
            "category": "linux",
            "tag": [
                {
                    "id": 1,
                    "title": "python"
                },
                {
                    "id": 2,
                    "title": "linux"
                }
            ],
            "status": 1,
            "title": "标题1",
            "summary": "这是第1篇",
            "content": "dafsdsfdsaf这是第11篇"
        },
        {
            "id": 2,
            "category": "python",
            "tag": [],
            "status": 1,
            "title": "标题2",
            "summary": "这是第二篇",
            "content": "dafsdsfdsaf这是第二篇"
        }
    ]
}

 

上一篇:Django restframework 分页

下一篇:Django restframework 筛选