Drf的Apiview、GenericView、Viewset和router的原理分析
目录
概述
从高到低的继承关系如下:
GenericViewSet(viewset) -drf GenericAPIView -drf APIView -drf View -django
这些view之间的差异就引出了drf中另一个核心点mixin
mixin包括:
CreateModelMixin ListModelMixin RetrieveModelMixin UpdateModelMixin DestroyModelMixin
以ListModelMixin为例做区别,如果我们不去继承这个mixin它里面的这些方法的话。
就无法将get 和 list连接起来。无法连接,那么list中所作的所有功能都不能完成。过滤,分页都将享受不到。
- RetrieveModelMixin对于具体的商品信息进行了获取,序列化。这个在后面的商品详情页会介绍到。
- UpdateModelMixin中对于部分更新还是全部更新进行了判断。
- DestroyModelMixin用来连接我们的delete方法,在我们delete时有一些必要的操作,如设置返回状态204等。
GenericAPIView 继承自APIView:新增加了过滤、分页、序列化
GenericAPIView结合各种mixin可以组合成ListAPIView、RetrieveAPIView、等等,新增了get、post等方法
GenericViewSet继承了GenericAPIView 和ViewSetMixin ,ViewSetMixin允许在url配置时进行绑定,例如使用router或者自己进行绑定
用法示例:
model.py
class Goods(models.Model): """ 商品 """ category = models.ForeignKey(GoodsCategory, verbose_name="商品类目") name = models.CharField(max_length=100, verbose_name="商品名") sold_num = models.IntegerField(default=0, verbose_name="商品销售量") goods_front_image = models.ImageField(upload_to="goods/images/", null=True, blank=True, verbose_name="封面图") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间") click_num = models.IntegerField(default=0, verbose_name="点击数") class Meta: verbose_name = '商品' verbose_name_plural = verbose_name def __str__(self): return self.name
采用django的view方法
views.py
第一种写法
但是有很多问题:一个一个取太麻烦,取datetime和imagefield会报错,无法做序列化
import json from django.http import HttpResponse class GoodsListView(View): def get(self,request): json_list=[] goods=Goods.objects.all() for good in goods: json_dict={} json_dict["name"]=good.name json_dict["category"]=good.category.name json_dict["sold_num"]=good.sold_num json_list.append(json_dict)
第二种写法
model_to_dict 将model转换为字典,不用一个字段一个字段提取,但还是存在datetime和imagefield无法序列化的问题
from django.forms.models import model_to_dict import json from django.http import HttpResponse class GoodsListView(View): def get(self,request): json_list=[] goods=Goods.objects.all() for good in goods: json_dict=model_to_dict(good) json_list.append(json_dict) return HttpResponse(json.dumps(json_list), content_type="application/json")
第三种写法
serializers 专门用于序列化,有了这个序列化,其实上面的model_to_dict都不用做了
import json from django.core import serializers from django.http import HttpResponse,JsonResponse class GoodsListView(View): def get(self,request): json_data=serializers.serialize("json",goods) json_data=json.loads(json_data) # 或者return HttpResponse(json.dumps(json_data), content_type="application/json") return JsonResponse(json_data,safe=False)
urls.py
url(r'^goods/$',GoodsListView.as_view(),name="good-list"),
drf中采用APIView
新建一个serializers.py
暂且用这两个字段作为示例
from rest_framework import serializers class GoodsSerializer(serializers.Serializer): name = serializers.CharField(required=True,max_length=100) click_num = serializers.IntegerField(default=0)
可以修改为以下,这样就可以把所有的字段都进行序列化
class GoodsSerializer(serializers.ModelSerializer): class Meta: model = Goods fields = "__all__"
views.py
class GoodsListView(APIView): """ List all goods """ def get(self, request, format=None): goods = Goods.objects.all() goods_serializer = GoodsSerializer(goods, many=True) return Response(goods_serializer.data)
drf采用GenericAPIView
views.py
class GoodsListView(mixins.ListModelMixin,generics.GenericAPIView): """ 商品列表页 """ queryset = Goods.objects.all() serializer_class = GoodsSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)
drf采用GenericViewSet
views.py
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet): """ 商品列表页 """ queryset = Goods.objects.all() serializer_class = GoodsSerializer
urls.py
将get请求绑定到list之上,类似于之前的
def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)
这样我们就不用自己再去绑定了。
配置url时就不用再加as_view()了
goods_list = GoodsListViewSet.as_view({ 'get': 'list', }) # 商品列表页 url('goods/', goods_list,name="goods-list"),
是我们可以更厉害一点,直接不用进行这个get 与list的绑定,它自动完成。那就是采用router
from goods.views import GoodsListViewSet from rest_framework.routers import DefaultRouter router=DefaultRouter() #配置goods的url router.register(r'goods', GoodsListViewSet,base_name='goods')
参考文档:https://blog.csdn.net/summer2day/article/details/81367781