zoukankan      html  css  js  c++  java
  • REST framework 视图

    前言

    在了解了REST farmwork封装的视图类之后,我对python的面向对象有了更深刻的理解。

    Django RESR framework框架内置的视图类充分发挥了面向对象封装与继承的特性。

    自己写一个类似于DRF内置视图类的功能

    实现一个图书出版社的增、删、改、查、查功能,两个查一个是查所有出版社,一个是查具体的某一个出版社。

    首先是一个简略的表结构设计models.py:

    from django.db import models
    
    class Publisher(models.Model):
        name = models.CharField(max_length=16)
    
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        name = models.CharField(max_length=16)
    
        def __str__(self):
            return self.name
    
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        CHOICES = ((1, 'Python'), (2, 'Go'), (3, 'Linux'))
        category = models.IntegerField(choices=CHOICES)
        pub_date = models.DateField()
        publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.title

    然后是路由url:

    将用到pk,与不用到pk的路由业务区分开

    from django.contrib import admin
    from django.urls import path, re_path
    from bms import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        # 查所有对象,与添加对象
        re_path(r'publishers/$', views.PublisherView.as_view()),
        # 带pk查询具体某一条数据
        re_path(r'publishers/(?P<pk>d+)/$', views.PublisherDetailView.as_view()),  # 出版社详情
    ]

    再到序列化类,自创建的serializers.py

    from bms import models
    from rest_framework import serializers
    
    
    class PublisherModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Publisher
            fields = "__all__"
    
    
    class AuthorModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Author
            fields = "__all__"

    最后视图views.py

    from bms import models
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from bms.serializers import PublisherModelSerializer
    
    
    ##################### 面向对象,手动实现REST framework视图功能##################
    class GenericView(APIView):
        '''公用类'''
        queryset = None
        serializer_class = None
    
        def get_queryset(self):
            # 让每一次请求来的时候都现查一次数据
            print('GeneriView------',self)
            return self.queryset.all()
    
        def get_object(self, request, pk):
            # 获取具体queryset
            return self.get_queryset().filter(pk=pk)
    
    class ListMixin(object):
        # mixi.n 混合类,不能单独使用,利用python支持多继承
        def get(self, request):
            print('ListMixin------------', self)
            queryset = self.get_queryset()
            ser_obj = self.serializer_class(queryset, many=True)
            return Response(ser_obj.data)
    
    
    class CreateMixin(object):
        def post(self, request):
            ser_obj = self.serializer_class(data=request.data)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response("ok")
            else:
                return Response(ser_obj.errors)
    
    
    class RetrieveMixin(object):
        """ 获取具体某一条记录"""
        def retrieve(self, request, pk):
            '''将此get方法与ListMixin中的get方法区分'''
            obj = self.get_object(request, pk).first()
            if obj:
                ser_obj = self.serializer_class(obj)
                return Response(ser_obj.data)
            else:
                return Response("无效的id")
    
    
    class UpdateMixin(object):
        def put(self, request, pk):
            obj = self.get_object(request, pk).first()
            if obj:
                ser_obj = self.serializer_class(instance=obj, data=request.data, partial=True)
                if ser_obj.is_valid():
                    ser_obj.save()
                    return Response(ser_obj.data)
                else:
                    return Response(ser_obj.errors)
            else:
                return Response("无效的id")
    
    
    class DestroyMixin(object):
        def delete(self, request, pk):
            obj = self.get_object(request, pk)
            if obj:
                obj.delete()
                return Response("删除成功")
            else:
                return Response("无效的id")
    
    
    class RetrieveView(GenericView, RetrieveMixin):
        '''因两个get方法相冲图,在此曲线访问查询具体对象的get方法'''
        def get(self, request, pk):
            return self.retrieve(request, pk)
    
    
    # 出版社
    class PublisherView(GenericView, ListMixin, CreateMixin):
        '''查所有出版社,增加出版社'''
        # 只用写配置项
        queryset = models.Publisher.objects.all()
        serializer_class = PublisherModelSerializer
    
    
    class PublisherDetailView(RetrieveView, UpdateMixin, DestroyMixin):
        '''查询具体某一出版社,编辑,删除'''
        queryset = models.Publisher.objects.all()
        serializer_class = PublisherModelSerializer

    这样写就实现了简单的增删改查查功能,而且用对象封装,如果要添加其他表的查询,只需要简单的6行代码就可以实现;

    比如:实现作者的增删改查查

    # 作者
    class AuthorListView(ListCreateAPIView):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer
    
    
    class AuthorDetailView(RetrieveUpdateDestroyAPIView):
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer

    利用面向对象的封装与继承极大地简化了代码,减少了代码冗余。

    但我们自己写的功能不够全面,不够严谨,Django REST framework 给我们封装了内置的视图类ModelViewSet。

    Django REST framework 视图组件

    视图组件是用来优化接口逻辑的

    首先看看ModelViewSet

    就是继承了5个混合类和一个公共类。

    mixins.py中就是那五个类,封装了增删改查查 5个方法,还有其他辅助功能的方法,结构与上面实现的类似。

    而使用这个视图类就更简单了,一张表只需要一个类

    from rest_framework.viewsets import ModelViewSet
    class AuthorViewSet(ModelViewSet):
        """
            内部封装了这五个方法
            list()
            create()
            retrieve()
            update()
            destroy()
    
        """
        queryset = models.Author.objects.all()
        serializer_class = AuthorModelSerializer

    因内置类中封装的方法与请求方式的名并不一样

    list()   对应查询所有对象的get方法

    create()   对应添加的post方法

    retrieve()  对应查询具体对像的get方法

    update()   对应更新对象的put方法

    destroy()   对应删除delete 方法

    所以url要设置 actions 让它们一一对应

    urlpatterns = [
        path('admin/', admin.site.urls),
        # 查所有对象,与添加对象
        re_path(r'publishers/$', views.PublisherView.as_view()),
        # 带pk查询具体某一条数据
        re_path(r'publishers/(?P<pk>d+)/$', views.PublisherDetailView.as_view()),  # 出版社详情
    
        re_path(r'authors/$', views.AuthorViewSet.as_view(actions={'get': 'list', 'post': 'create'})),  # 作者列表
        re_path(r'authors/(?P<pk>d+)/$', views.AuthorViewSet.as_view(
            actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})
            ),  # 作者详情
    ]

    并且REST framework还封装了路由类,上面关于authors的路由还可以这样写

    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    router.register('authors', views.AuthorViewSet)
    
    urlpatterns += router.urls

    不过这样写路由,业务关系不清晰,一般用的少。

  • 相关阅读:
    逻辑运算符&逻辑短路
    python运算符&优先性
    python类型强转&二级容器
    python中转义符&str格式化
    python中变量的缓存机制
    底层二进制的计算
    python容器数据类型的特色
    进制的转化
    shell脚本学习(1)-菜鸟教程
    python中yield的用法-简单明了!
  • 原文地址:https://www.cnblogs.com/zwq-/p/10269169.html
Copyright © 2011-2022 走看看