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这是第二篇"
}
]
}