• 第四章 restframework——视图组件


    第四章 restframework——视图组件

    一、基本视图

    二、mixin模块+generics模块(GenericAPIView类)编写视图

    三、generics模块下的ListCreateAPIView,RetrieveUpdateDestroyAPIView

    四、viewsets模块下的ModelViewSet

    一、基本视图

     回顾上一章节的序列化组件,你会发现views里的代码逻辑部分大同小异

    代码如下:

    from django.db import models
    
    # Create your models here.
    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        # def __str__(self):
        #     return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name
    models.py

    urls.py

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publishes/$',views.PublishView.as_view()),
        url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),
        url(r'^books/$',views.BookView.as_view()),
        url(r'^books/(d+)/$',views.BookDetailView.as_view())
    ]
    from django.shortcuts import *
    from django.views import View
    from .models import *
    import json
    # Create your views here.
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .all_serializers import *
    
    # class BookSerializers(serializers.Serializer):
    #     title = serializers.CharField(max_length=32)
    #     price = serializers.IntegerField()
    #     pub_date = serializers.DateField()
    #     publish = serializers.CharField(source="publish.name")
    #     # authors=serializers.CharField(source="authors.all") #这样会返回queryset对象,看起来还不是特别舒服
    #     authors = serializers.SerializerMethodField() # 这个方法只是为多对多服务的,下面要写类似钩子的方法
    #     def get_authors(self,obj):
    #         temp = []
    #         for obj in obj.authors.all():
    #             temp.append(obj.name)
    #         return temp
    
    class BookView(APIView):
        def get(self,request):
            # get请求数据
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list,many=True)
            '''
            序列化BookSerializers(book_list,many=True)做了如下操作:
            temp = []
            for obj in book_list:
                temp.append({
                    "title":obj.title,
                    "price":obj.price,
                    "pub_date":obj.pub_date,
                    "publish":obj.publish,   # 这里的返回值就是上面get_authors的返回值
                })                  
            '''
            return Response(bs.data)
    
        def post(self,request):
            # post请求数据
            bs = BookModelSerializers(data=request.data)
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()  # create方法
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)
    
    
    class BookDetailView(APIView):
        def get(self,request,id):
            book = Book.objects.filter(pk=id).first()
            bs = BookModelSerializers(book)
            return Response(bs.data)
        def put(self,request,id):
            book = Book.objects.filter(pk=id).first()
            # 因为是做更新操作,所以要写data=request.data,把新数据放进去
            bs = BookModelSerializers(book,data=request.data)
            if bs.is_valid():
                bs.save()
                return Response(bs.data)
            else:
                return Response(bs.errors)
        def delete(self,request,id):
            Book.objects.filter(pk=id).delete()
            # 删除操作返回空即可
            return Response()
    
    
    class PublishView(APIView):
        def get(self, request):
            publish_list = Publish.objects.all()
            ps = PublishModelSerializers(publish_list, many=True)
            return Response(ps.data)
            # 取数据
            # print('restframework', request.data)
            # print('restframework type', type(request.data))
            # print('restframework', request._request.GET)
            # print('restframework type', type(request._request.GET))
            # print('restframework', request.GET)
            # print('restframework type', type(request.GET))
            # return HttpResponse('ok')
            # 序列化
            # publish_list = Publish.objects.all()    #queryset对象
            # pb = PublishSerializers(publish_list, many=True)
            # many = true 代表前面传入的参数是queryset对象
            # print(pb.data)
    
            # publish1 = Publish.objects.filter(pk=1).first()
            # print(publish1)        # publish对象
            # pb = PublishSerializers(publish1,many=False)
            # PublishSerializers(model_obj,many = false)
            # many = false 代表前面传入的参数是model对象
            # 默认many = false,所以如果是model对象可以不用写many
            # print(pb.data)
            # return HttpResponse(pb.data)
    
            # 方式一
            # publish_list = list(Publish.objects.all().values('name','email'))
            # return HttpResponse(json.dumps(publish_list))
            # 方式二
            # from django.forms.models import model_to_dict
            # publish_list = Publish.objects.all()
            # temp = []
            # for obj in publish_list:
            #     temp.append(model_to_dict(obj))
            # return HttpResponse(json.dumps(temp))
            # 方式三
            # from django.core import serializers
            # publish_list = Publish.objects.all()
            # temp = serializers.serialize("json",publish_list)
            # return HttpResponse(temp)
    
        def post(self, request):
            # 取数据
            # 原生的request操作
            # print('POST',request.POST)
            # print('body',request.body)
            # print(type(request))
            # from django.core.handlers.wsgi import WSGIRequest
            # print(request.data)
            # 新的request支持的操作
            # 要想使用之前request的方法
            # ret = request._request.POST
            # django将request的所有方法的数据获取进行了不同的封装
            # 而restframework将request下POST方法的数据封装成request.data
            # print('restframework',request.data)
            # print('restframework type',type(request.data))
            # return HttpResponse('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()
    views.py
    from rest_framework import serializers
    from .models import *
    
    # 为queryset,model对象做序列化
    # class PublishSerializers(serializers.Serializer):
    #     # 下面写的字段取决于你需要哪些字段做序列化
    #     name = serializers.CharField()
    #     email = serializers.CharField()
    
    class PublishModelSerializers(serializers.ModelSerializer):
        class Meta:
            model=Publish
            fields="__all__"
    
    
    class BookModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Book # 表名
            fields = "__all__" # 默认把所有字段写入,不包括自己写的get_authors方法
            # field = ['nid','title','authors','publish'] # 指定字段
            # exclude = ('nid')  # 除了...字段,不能跟fields同时用
            # depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
        # 如果要指定一对多,或多对多显示的字段需要重写create方法
        publish = serializers.CharField(source='publish.pk')
        authors = serializers.CharField(source="authors.all")
        def create(self, validated_data):
            # print('validated_data',validated_data)
            book = Book.objects.create(
                title=validated_data['title'],
                price=validated_data['price'],
                pub_date=validated_data['pub_date'],
                publish_id=validated_data['publish']['pk']
            )
            book.authors.add(*validated_data['authors'])
            return book
    all_serializers.py

    二、mixin模块+generics模块(GenericAPIView类)编写视图

    尝试用mixin类写一个AuthorView,对比下它的简便。

    【mixin模块】

    导入模块

    from rest_framework import mixins

    先简单熟悉下mixin模块下的几个class,它对应了restful的规范

    查看下ListModeMixin的源码,与之前写的get方法对应起来看下

    查看下CreateModeMixin的源码,与之前写的get方法对应起来看下

    其他的将不再做对比,你会发现其实restframework替我们做了功能封装避免重复代码,那我们用mixin尝试写AuthorView看看

    urls.py

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        url(r'^authors/$',views.AuthorView.as_view(),name='authors'),
        url(r'^authors/(?P<pk>d+)/$',views.AuthorDetailView.as_view(),name='author_detail'),
    
        url(r'^publishes/$',views.PublishView.as_view(),name='publishes'),
        url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),
    
        url(r'^books/$',views.BookView.as_view(),name='books'),
        url(r'^books/(d+)/$',views.BookDetailView.as_view(),name='book_detail'),
    ]

    all_serializers.py

    class AuthorModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Author
            fields = "__all__"

     【generics模块

     导入模块

    from rest_framework import generics

    views.py

    注意:

    ①类必须继承generics.GenericAPIView

    ②切记:queryset和serializer_class 这两个名字不能改,固定写法,否则会出现如下报错

    AssertionError: 'AuthorView' should either include a `queryset` attribute, or override the `get_queryset()` method.

    from rest_framework import mixins
    from rest_framework import generics
    
    class AuthorView(
            mixins.ListModelMixin,
            mixins.CreateModelMixin,
            generics.GenericAPIView
        ):
        # GenericAPIView继承了之前的APIView
        # !!!切记:queryset和serializer_class 这两个名字不能改!!!
        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 put(self,request,*args,**kwargs):
            return self.update(request,*args,**kwargs)
        def delete(self,request,*args,**kwargs):
            return self.destroy(request,*args,**kwargs)

    四、generics模块下的ListCreateAPIView,RetrieveUpdateDestroyAPIView

    上面我们看了mixin模块及generics模块的确节省了大量代码,可是还是存在重复代码,此时我们再来看下generics模块下的类们。

    通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。

    还是用author举例:

    导入模块

    from rest_framework import generics

    views.py

    class AuthorView(generics.ListCreateAPIView):
        queryset = Author.objects.all()
        serializer_class = AuthorModelSerializers
    
    class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
        queryset = Author.objects.all()
        serializer_class = AuthorModelSerializers

    对比下看看

    五、viewsets模块下的ModelViewSet

    像上面所述,还是有重复代码,别急,还有更简便的。

    记住核心在于,利用字典的形式指定请求方法(get、post...)的操作(list,create....)

    导入模块

    from rest_framework import viewsets

    urls.py

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
    
        # url(r'^authors/$',views.AuthorView.as_view(),name='authors'),
        # url(r'^authors/(?P<pk>d+)/$',views.AuthorDetailView.as_view(),name='author_detail'),
    
        url(r'^authors/$',views.AuthorModelView.as_view({"get":"list","post":"create"}),name='authors'),
        url(r'^authors/(?P<pk>d+)/$',views.AuthorModelView.as_view({
                    'get': 'retrieve',
                    'put': 'update',
                    'patch': 'partial_update',
                    'delete': 'destroy'
                }),name='author_detail'),
    
        url(r'^publishes/$',views.PublishView.as_view(),name='publishes'),
        url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),
    
        url(r'^books/$',views.BookView.as_view(),name='books'),
        url(r'^books/(d+)/$',views.BookDetailView.as_view(),name='book_detail'),
    ]

    views.py

    from rest_framework import viewsets
    class AuthorModelView(viewsets.ModelViewSet):
        queryset = Author.objects.all()
        serializer_class = AuthorModelSerializers

    如果你想用自己方法来处理请求,只需自己重写函数,并更改路由即可

  • 相关阅读:
    线程同步的三种方式(Mutex,Event,Critical Section) 沧海
    VC++多线程下内存操作的优化 沧海
    C++内存对象大会战 沧海
    技术关注:搜索引擎经验 沧海
    jira 3.13.5版 安装 配置 用户权限控制 拂晓风起
    C++ int string 转换 拂晓风起
    C++调用C链接库会出现的问题 拂晓风起
    Windows Server 2003 IIS Service Unavailable 问题解决 拂晓风起
    研究 学术 开发 的好用工具(不包括常见的) 拂晓风起
    SGMarks 问世 (Firefox扩展Gmarks的扩展版) 纯属学习 拂晓风起
  • 原文地址:https://www.cnblogs.com/neymargoal/p/9791004.html
Copyright © 2020-2023  润新知