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等方法
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')