暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

drf | Django 为什么推荐用 drf 的 ViewSet来开发!

零点小思随笔 2021-06-24
780

商品列表页的开发涉及大部分 DRF 的基础知识,接下来就以商品列表页的开发来介绍 DRF,从Django 最底层的View 开始,到最终用 DRF 的ViewSet来实现。

1、DRF 安装

在虚拟环境中安装 DRF。

pip install djangorestframework
pip install markdown
pip install django-filter
pip install django-guardian

把 rest_framework 加入到 settings 的 INSTALLED_APPS 中:

INSTALLED_APPS = [
   ...
   'rest_framework',
]

配置 DRF 登录的路由

urlpatterns = [
   ...
   path('api-auth/', include('rest_framework.urls'))
]

2、APIView

DRF 的 APIView 继承自 Django 的 View,在此基础上实现了不少功能。

使用 DRF 的 APIView 和 serializers 实现列表页。

2.1、views:

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

from .models import Goods
from .serializers import GoodsSerializer


class GoodsListView(APIView):
   """
   List all goods.
   "
""
   def get(self, request, format=None):
       goods = Goods.objects.all()
       # goods 为列表,所以要设置 many=True
       data_serializer = GoodsSerializer(goods, many=True)
       return Response(data_serializer.data)

   def post(self, request, format=None):
       serializer = GoodsSerializer(data=request.data)
       if serializer.is_valid():
           serializer.save()
           return Response(serializer.data, status=status.HTTP_201_CREATED)
       return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

  • 使用 DRF 的 serializers 序列化。
  • 使用 DRF 的 Response 返回数据。

2.2、serializers:

  • serializers.Serializer
from rest_framework import serializers


class GoodsSerializer(serializers.Serializer):
   id = serializers.IntegerField(read_only=True)
   is_hot = serializers.BooleanField(required=False)
   name = serializers.CharField(max_length=300, verbose_name="商品名")
   click_num = serializers.IntegerField(default=0, verbose_name="点击数量")

  • serializers.ModelSerializer
class GoodsSerializer(serializers.ModelSerializer):
   class Meta:
       model = Goods
       # fields = ('id', name', 'click_num', 'is_hot')
       fields = "__all__"

  • all:取出 model 里的所有字段。

ModelSerializer 的写法比 Serializer 更简洁。

如果需要外键的详细信息,可以用 ModelSerializer 的嵌套用法:

class GoodsImageSerializer(serializers.ModelSerializer):
   class Meta:
       model = GoodsCategory
       fields = "__all__"


class GoodsSerializer(serializers.ModelSerializer):
   category = CategorySerializer()

   class Meta:
       model = Goods
       # fields = ('name', 'click_num', 'market_price', 'add_time')
       fields = "__all__"

这样就可以在接口中看到外键信息。

3、mixins.* 与 generics.*

这里用比 APIView 更上层的方法来实现,可以让代码更加简洁。

generics.GenericAPIView 继承自 APIView。

3.1、

class GoodsListView(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
                   generics.GenericAPIView):
   """
   List all goods.
   "
""
   queryset = Goods.objects.all()
   serializer_class = GoodsSerializer

   # 必须重载以下函数
   def get(self, request, *args, **kwargs):
       return self.list(request, *args, **kwargs)

   def post(self, request, *args, **kwargs):
       return self.create(request, *args, **kwargs)

   def put(self, request, *args, **kwargs):
       return self.update(request, *args, **kwargs)

   def delete(self, request, *args, **kwargs):
       return self.destroy(request, *args, **kwargs)

3.2、

要重载函数,看起来还是不够简洁,要是能把这些方法给封装起来就好了。


  • ListAPIView 封装了 get 方法。
  • RetrieveAPIView 封装了 get 方法。
  • CreateAPIView 封装了 post 方法。
  • DestroyAPIView 封装了 delete 方法。
  • UpdateAPIView 封装了 put 和 patch 方法。
  • ListCreateAPIView 组合封装了 get 、 post 方法。
  • RetrieveDestroyAPIView 组合封装了 get 、 delete 方法。
  • RetrieveUpdateAPIView 组合封装了 get 、 put、patch 方法。
  • RetrieveUpdateDestroyAPIView 组合封装了 get 、 put、patch、 delete 方法。

3.3、

那么现在实现列表页就简洁多了,直接继承 ListAPIView。

class GoodsListView(generics.ListAPIView):
   """
   List all goods.
   "
""
   queryset = Goods.objects.all()
   serializer_class = GoodsSerializer

实际工作中,根据业务需要,使用不同的 APIView 组合即可。

4、viewsets.*

这里使用比 APIView 更高级的用法来实现商品列表页列表页

from rest_framework import viewsets

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    list:
      商品列表页
    "
""
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination

ViewSets 和 Routers 是配合起来使用的。

from .views import GoodsViewSet
from rest_framework import renderers

snippet_list = GoodsViewSet.as_view({
    'get''list',
})

还有没有更好的 router 配置呢?

from rest_framework.routers import DefaultRouter

router = DefaultRouter()
# 配置商品url
router.register(r'goods', views.GoodsViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

这是常用的 router 绑定方案。

5、自定义分页

列表页的数据通常是需要分页的,DRF 实现分页也很简单。

from rest_framework.pagination import PageNumberPagination

class GoodsPagination(PageNumberPagination):
    """
    自定义分页功能
    "
""
    page_size = 10
    page_size_query_param = 'page_size'
    page_query_param = "pageNo"
    max_page_size = 30

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    list:
      商品列表页
    "
""
    queryset = Goods.objects.all()
    # 序列化
    serializer_class = GoodsSerializer
    # 分页
    pagination_class = GoodsPagination

上面介绍了那么多列表页的开发方法,最主要的是介绍 viewsets 这种方案。

继承关系:
        GenericViewSet(viewset)   -- drf
            GenericAPIView        -- drf
                APIView           -- drf
                    View          --django
mixin:
        CreateModelMixin
        ListModelMixin
        RetrieveModelMixin
        UpdateModelMixin
        DestroyModelMixin


文章转载自零点小思随笔,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论