drf的APIView、GenericAPIView、GenericViewSet

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/summer2day/article/details/81367781

drf(django rest framework)都很多api都可以实现listview的功能,对于他们的用法区别做了下总结。因为我也是初学者,也比较混乱,很多不全面或者不对的地方,欢迎指正。

详细内容见http://www.django-rest-framework.org/api-guide/generic-views/
从高到低的继承关系如下:

GenericViewSet(viewset)            -drf
    GenericAPIView(generics)       -drf
        APIView(views)             -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等方法

image
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

1.采用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"),

2.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)

3.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)

4.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')

猜你喜欢

转载自blog.csdn.net/summer2day/article/details/81367781