REST-framework快速构建API--四部曲

作者:@skyflask
转载本文请注明出处:https://www.cnblogs.com/skyflask/p/10398679.html


目录

一、使用原生APIView
二、使用mixins
三、使用generics
四、使用viewsets

代码目录结构:

 

一、使用原生APIView

使用rest-framework原生的APIView实现过程:

以url(r'^books/$', views.BookView.as_view(),name="books")为例进行流程分析,

  • 1、views.BookView.as_view()==>APIView的as_view方法==>父类【View】的as_view方法
  • 2、View的as_view方法实际上是返回了View下的view方法
  • 3、view实际上是执行了dispatch方法
  • 4、dispatch执行过程是去找对应的get/post/put/delete/patch方法

代码实现如下:

urls文件

PublishView用于处理publishes的get和post,获取多个资源的情况

PublishDetailView用于处理publishes/1/的get、put、delete,获取单个资源的情况

1
2
url(r'^publishes/$', views.PublishView.as_view(),name="publish"),
url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(),name="detailpublish"),

  

views文件

使用rest-framework原生的APIView,按照上面说的流程,最后进入dispatch方法,所以只需要我们自己重写get/post/put/delete等方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from rest_framework.views import APIView
# Publish表
class PublishView(APIView):
    def get(self,request):
   
        publish_list = Publish.objects.all()
        ps = PublishModelSerializers(publish_list, many=True)
        return Response(ps.data)
 
    def post(self,request):
 
        # post请求的数据
        ps = PublishModelSerializers(data=request.data)
        if ps.is_valid():
            print(ps.validated_data)
            ps.save()  # create方法
            return Response(ps.data)
        else:
            return Response(ps.errors)
class PublishDetailView(APIView):
    def get(self, request, pk):
 
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish)
        return Response(ps.data)
 
    def put(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish, data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)
 
    def delete(self, request, pk):
        Publish.objects.filter(pk=pk).delete()
 
        return Response()

  

serializer文件

通过ModelSerializer类,指定model和fields进行序列化操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
from rest_framework import serializers
 
from app01.models import *
# 为queryset,model对象做序列化
class PublishSerializers(serializers.Serializer):
    name = serializers.CharField()
    email = serializers.CharField()
 
 
class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model=Publish
        fields="__all__"

  

原生APIView的缺点

针对每个model,需要自己写API的各种方法,代码重复程度很高。

进一步解决办法:使用mixins

二、使用mixins

mixins在上一步的基础上进行了进一步的封装,也就是把多资源情况下的GET/POST以及单资源情况下的GET/POST/PUT/DELETE进行了再次封装,只要我们指定集成的类,然后重写对应的方法即可,urls也不用变更。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from rest_framework import mixins
from rest_framework import generics
 
class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
    queryset=Author.objects.all()
    serializer_class =AuthorModelSerializers
 
    def get(self,request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    def post(self,request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
 
 
class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers
 
    def get(self,request,*args, **kwargs):
        return self.retrieve(request,*args, **kwargs)
 
    def delete(self,request,*args, **kwargs):
        return self.destroy(request,*args, **kwargs)
 
    def put(self,request,*args, **kwargs):
        return self.retrieve(request,*args, **kwargs)

  

使用mixins还是有代码重复的缺点,每个model表都需要重写这一堆方法和类。

 

三、使用generics

使用generics可以很好的避免上面的问题,他直接包含了多资源和单资源情况下的所有方法,而不需要重写get、post、put、delete方法,甚至还包括patch方法。

1
2
3
4
5
6
7
8
9
10
11
from rest_framework import mixins
from rest_framework import generics
 
 
class AuthorView(generics.ListCreateAPIView):
    queryset=Author.objects.all()
    serializer_class =AuthorModelSerializers
 
class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

  但是这里还有一个缺点,就是单资源和多资源的视图函数以及url都是两份,是不是可以进行一步封装呢?

四、使用viewsets

使用viewsets可以通过在as_view中传参进一步简化操作。

在as_view中传入{动作:方法}的字典给action参数,然后通过getattr和setattr方法进行参数解析,然后通过dispatch中执行对应的方法。

urls文件

1
2
3
4
5
6
7
url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"),
    url(r'^books/(?P<pk>\d+)$', views.BookViewSet.as_view({
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            }),name="book_detail"),

  

views文件

1
2
3
class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

  

这就是最终版本,对于一个model表,url两个,一个ModelViewSet类就可以轻易的实现一个API!

进一步简化

我们可以看到urls里面看上去是不是很乱的样子,其实,rest-framework也已经解决了这个脏乱差的问题,通过使用routers!

urls文件修改

以books为例:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.conf.urls import url,include
from django.contrib import admin
from rest_framework import routers
from app01 import views
 
 
#router实例化,并将Viewset进行注册
router = routers.DefaultRouter()
router.register(r'books',views.BookViewSet)
 
 
#路由控制
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publishes/$', views.PublishView.as_view(),name="publish"), #  View:view(request)=====APIView:dispatch()
    url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(),name="detailpublish"), #  View:view(request)=====APIView:dispatch()
 
    url(r'',include(router.urls)),
         
]

 

  

其他Viewset需要实例化,同样的操作即可,urls的最终结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.conf.urls import url,include
from django.contrib import admin
from rest_framework import routers
from app01 import views
 
 
#router实例化,并将Viewset进行注册
router = routers.DefaultRouter()
router.register(r'books',views.BookViewSet)
router.register(r'books',views.PublishViewSet)
 
 
#路由控制
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'',include(router.urls)),
         
]

  是不是很简洁?

 

posted @   skyflask  阅读(365)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示