• DRF 视图


    一.DRF中的Request

    在Django REST Framework中内置的Request类扩展了Django中的Request类, 实现了很多方便的功能 -- 如请求数据解析和认证等.

    比如, 区别于Django中的request: 从request.GET中获取URL参数, 从request.POST中去取某些情况下的POST数据(前端提交过来的数据).

    在APIView中封装的request, 就实现了请求数据的解析:

    • 对于GET请求的参数, APIView通过request.query_params来获取
    • 对于POST请求、PUT请求的数据, APIView通过request.data来获取

    二.前戏: 关于面向对象的继承

    # 讲一个葫芦娃的故事
    
    class Wa1(object):
        name = "红娃"
    
        def f1(self):
            print("力大无穷!")
    
    
    class Wa2(object):
        name = '橙娃'
    
        def f2(self):
            print('千里眼顺风耳!')
    
    
    class Wa3(object):
        name = '黄娃'
    
        def f3(self):
            print('钢筋铁骨!')
    
    
    class Wa4(object):
        name = '绿娃'
    
        def f4(self):
            print("会喷火!")
    
    
    class Wa5(object):
        name = '青蛙'
    
        def f5(self):
            print("会喷水!")
    
    
    class Jishuwa(Wa1, Wa3, Wa5):
        name = '奇数娃'
    
        def ff(self):
            print("我是{}, 我会:".format(self.name))
            self.f1()
            self.f3()
            self.f5()
    
    
    class Oushuwa(Wa2, Wa4):
        name = '偶数娃'
    
        def ff(self):
            print("我是{}, 我会:".format(self.name))
            self.f2()
            self.f4()
    
    
    jsw = Jishuwa()
    jsw.ff()
    osw = Oushuwa()
    osw.ff()
    
    
    # 直接定义一个基数娃
    class Taowa(Wa1, Wa3, Wa5):
        name = '套娃'
    
        def ff(self):
            print("我是{}, 我会:".format(self.name))
            self.f1()
            self.f3()
            self.f5()
    
    
    class Wawa(Taowa):
        pass
    
    
    print("=" * 120)
    a = Wawa()
    a.ff()
    

    三.初级版本

    1. settings.py文件 -- 注册app

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'bms.apps.BmsConfig',
        'rest_framework',	# 注册app
    ]
    

    2. models.py文件 -- 创建表

    from django.db import models
    
    # 出版社表
    class Publisher(models.Model):
        name = models.CharField(max_length=32)
    
        def __str__(self):
            return self.name
    
    # 书籍表
    class Book(models.Model):
        title = models.CharField(max_length=32)
        publisher = models.ForeignKey(to='Publisher', to_field='id', on_delete=models.CASCADE)
    
        def __str__(self):
            return self.title
    
    # cd到当前项目目录
    # 执行数据库迁移指令
    python manage.py makemigrations
    python manage.py migrate
    

    3. admin.py文件

    from django.contrib import admin
    from bms import models	# bms是我们的app
    
    admin.site.register(models.Publisher)
    admin.site.register(models.Book)
    
    # 创建超级用户
    # cd到当前项目目录
    python manage.py createsuperuser
    
    # 启动Django项目
    python manage.py runserver 127.0.0.1:8000
    
    # 浏览器地址栏输入 127.0.0.1:8000
    # 输入账号和密码,进入admin页面,对数据库中的表 添加或修改相关数据
    

    4. 根目录下urls.py -- 路由匹配

    from django.conf.urls import url
    from django.contrib import admin
    from bms import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        
        url(r'^book/$', views.BookListView.as_view()),
        url(r'^book/(?P<pk>d+)$', views.BookDetailView.as_view()),
    ]
    

    5. bms/views.py -- 视图函数

    from rest_framework.response import Response
    from rest_framework.views import APIView
    from bms import models
    from bms.modelserializers import BookModelSerializer
    
    
    class BookListView(APIView):
        def get(self, request):
            # 1.从数据库查询出所有书籍对象
            queryset = models.Book.objects.all()
            # 2.使用modelserializer对获取的对象进行序列化
            ser_obj = BookModelSerializer(queryset, many=True)
            return Response(ser_obj.data)
    
        def post(self, request):
            # 1.获取前端提交过来的数据 --> request.data
            # 2.对数据进行有效性校验
            ser_obj = BookModelSerializer(data=request.data)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response('添加成功!')
            else:
                return Response(ser_obj.errors)
    
    
    class BookDetailView(APIView):
        def get(self, request, pk):  # get获取具体某本书的信息
            # 1.根据pk去数据库中查询具体的那本书籍对象
            book_obj = models.Book.objects.filter(pk=pk).first()
            if book_obj:
                # 2.将书籍对象 序列化成 json格式的数据
                ser_obj = BookModelSerializer(book_obj)
                # 3.返回响应
                return Response(ser_obj.data)
            else:
                return Response('无效的书籍id')
    
        def put(self, request, pk):  # put修改具体某本书的信息
            # 1.根据pk去查询具体的那本书籍对象
            book_obj = models.Book.objects.filter(pk=pk).first()
            if book_obj:
                # 2.获取用户发送过来的数据并修改数据
                ser_obj = BookModelSerializer(instance=book_obj, data=request.data, partial=True)
                if ser_obj.is_valid():
                    # 3.保存并返回修改后的数据
                    ser_obj.save()
                    return Response(ser_obj.data)
                else:
                    return Response(ser_obj.errors)
            else:
                return Response('无效的书籍id')
    
        def delete(self, request, pk):  # delete删除具体某一本书籍对象
            # 1.根据pk去查询具体的那本书籍对象
            book_obj = models.Book.objects.filter(pk=pk).first()
            if book_obj:
                # 2.删除该书籍对象
                book_obj.delete()
                return Response('删除成功')
            else:
                return Response('无效的书籍id')
    

    6. bms/modelserializers.py -- 自定义序列化工具

    from rest_framework import serializers
    from bms import models
    
    
    class PublisherSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        name = serializers.CharField()
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        publisher_info = serializers.SerializerMethodField(read_only=True)
    
        def get_publisher_info(self, book_obj):
            return PublisherSerializer(book_obj.publisher).data
    
        class Meta:
            model = models.Book
            fields = '__all__'
            extra_kwargs = {
                'publisher': {'write_only': True},
            }
    
    
    class PublisherModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Publisher
            fields = '__all__'
    

    四.进化版: 使用自定义混合类和自定义通用类

    提取出views.py文件中函数BookListViewBookDetailView代码中的重复部分, 并将这些重复部分封装为通用类(Generic)混合类(Mixin), 利用Python强大的多继承功能, 将代码进一步优化. 充分体现Python语言的"优雅"和"简洁".

    注意: 混合类Mixin不能单独实例化, 需要与其他的类搭配使用.

    bms/views.py:

    from rest_framework.response import Response
    from rest_framework.views import APIView
    from bms import models
    from bms.modelserializers import BookModelSerializer, PublisherModelSerializer
    
    
    # 通用功能
    class GenericView(APIView):
        queryset = None
        serializer_class = None
    
        def get_queryset(self, request, *args, **kwargs):
            # 再一次调用all()方法: 让每次请求来的时候都重新查一次数据
            return self.queryset.all()
    
        def get_obj(self, request, pk, *args, **kwargs):
            return self.get_queryset(request, *args, **kwargs).filter(pk=pk).first()
    
    
    # get展示(全部)资源
    class ListMixin(object):
        def get(self, request):
            queryset = self.get_queryset(request)
            ser_obj = self.serializer_class(queryset, many=True)
            return Response(ser_obj.data)
    
    
    # post添加资源
    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('添加成功!')
            else:
                return Response(ser_obj.errors)
    
    
    # get展示(部分)资源
    class RetrieveMixin(object):
        def get(self, request, pk, *args, **kwargs):
            obj = self.get_obj(request, pk, *args, **kwargs)
            if obj:
                ser_obj = self.serializer_class(obj)
                return Response(ser_obj.data)
            else:
                return Response('无效的id!')
    
    
    # put更新(修改)资源
    class UpdateMixin(object):
        def put(self, request, pk, *args, **kwargs):
            obj = self.get_obj(request, pk, *args, **kwargs)
            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!')
    
    
    # delete删除资源
    class DestroyMixin(object):
        def delete(self, request, pk, *args, **kwargs):
            obj = self.get_obj(request, pk, *args, **kwargs)
            if obj:
                obj.delete()
                return Response('删除成功!')
            else:
                return Response('无效的id!')
    
    
    class BookListView(GenericView, ListMixin, CreateMixin):
        queryset = models.Book.objects.all()
        serializer_class = BookModelSerializer
    
    
    class BookDetailView(GenericView, RetrieveMixin, UpdateMixin, DestroyMixin):
        queryset = models.Book.objects.all()
        serializer_class = BookModelSerializer
    
    
    class PublisherListView(GenericView, ListMixin, CreateMixin):
        queryset = models.Publisher.objects.all()
        serializer_class = PublisherModelSerializer
    
    
    class PublisherDetailView(GenericView, RetrieveMixin, UpdateMixin, DestroyMixin):
        queryset = models.Publisher.objects.all()
        serializer_class = PublisherModelSerializer
    

    urls.py:

    from django.conf.urls import url
    from django.contrib import admin
    from bms import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        
        url(r'^book/$', views.BookListView.as_view()),
        url(r'^book/(?P<pk>d+)$', views.BookDetailView.as_view()),
    	url(r'^publisher/$', views.PublisherListView.as_view()),
        url(r'^publisher/(?P<pk>d+)$', views.PublisherDetailView.as_view()),
    ]
    

    五.超级进化版: 使用GenericViewSet通用类

    GenericViewSetrest_framework这个app中已经封装好了的一个类:

    from rest_framework.viewsets import GenericViewSet
    

    需要注意的是, 继承了GenericViewSet以后, GenericViewSet这个类已经帮我们封装好了get_queryset()get_object()这两个方法, 它们不需要接收参数, 我们直接调用即可.

    bms/views.py:

    from rest_framework.response import Response
    from bms import models
    from bms.modelserializers import BookModelSerializer, PublisherModelSerializer
    from rest_framework.viewsets import GenericViewSet	# 引入GenericViewSet通用类
    
    
    # get展示(全部)资源
    class ListMixin(object):
        def list(self, request, *args, **kwargs):
            queryset = self.get_queryset()
            ser_obj = self.serializer_class(queryset, many=True)
            return Response(ser_obj.data)
    
    
    # post添加资源
    class CreateMixin(object):
        def create(self, request, *args, **kwargs):
            ser_obj = self.serializer_class(data=request.data)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response('添加成功!')
            else:
                return Response(ser_obj.errors)
    
    
    # get展示(部分)资源
    class RetrieveMixin(object):
        def retrieve(self, request, pk, *args, **kwargs):
            obj = self.get_object()
            if obj:
                ser_obj = self.serializer_class(obj)
                return Response(ser_obj.data)
            else:
                return Response('无效的id!')
    
    
    # put更新(修改)资源
    class UpdateMixin(object):
        def update(self, request, pk, *args, **kwargs):
            obj = self.get_object()
            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!')
    
    
    # delete删除资源
    class DestroyMixin(object):
        def destroy(self, request, pk, *args, **kwargs):
            obj = self.get_object()
            if obj:
                obj.delete()
                return Response('删除成功!')
            else:
                return Response('无效的id!')
    
    
    class BookViewSet(GenericViewSet, ListMixin, CreateMixin, RetrieveMixin, UpdateMixin, DestroyMixin):
        queryset = models.Book.objects.all()
        serializer_class = BookModelSerializer
    
    
    class PublisherViewSet(GenericViewSet, ListMixin, CreateMixin, RetrieveMixin, UpdateMixin, DestroyMixin):
        queryset = models.Publisher.objects.all()
        serializer_class = PublisherModelSerializer
    

    urls.py:

    from django.conf.urls import url
    from django.contrib import admin
    from bms import views
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        
    	url(r'^book/$', views.BookViewSet.as_view(actions={'get': 'list', 'post': 'create'})),
        url(r'^book/(?P<pk>d+)$', views.BookViewSet.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
        url(r'^publisher/$', views.PublisherViewSet.as_view(actions={'get': 'list', 'post': 'create'})),
        url(r'^publisher/(?P<pk>d+)$', views.PublisherViewSet.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
    ]
    

    六.究极进化版: 使用rest_framework帮我们封装好的通用类和混合类

    bms/views.py:

    from bms import models
    from bms.modelserializers import BookModelSerializer, PublisherModelSerializer
    from rest_framework.viewsets import ModelViewSet
    
    
    class BookViewSet(ModelViewSet):
        queryset = models.Book.objects.all()
        serializer_class = BookModelSerializer
    
    
    class PublisherViewSet(ModelViewSet):
        queryset = models.Publisher.objects.all()
        serializer_class = PublisherModelSerializer
    

    七.终极进化版: 使用rest_framework帮我们封装好的路由DefaultRouter

    from rest_framework.routers import DefaultRouter
    from bms import views
    
    urlpatterns = []
    
    router = DefaultRouter()
    router.register('book', views.BookViewSet)
    router.register('publisher', views.PublisherViewSet)
    
    # 重写urlpatterns
    urlpatterns += router.urls
    
  • 相关阅读:
    v-model的实现原理
    面试技巧
    Vue中使用mui的tab-top-webview-main完成分类滑动栏出现兼容问题如何解决
    前端jquery面试题个人总结
    下拉复选框
    什么是BFC
    CSS控制文本自动换行
    CSS+DIV布局中absolute和relative区别
    2种方式解决vue路由跳转未匹配相应路由避免出现空白页面或者指定404页面
    vue页面无操作10分钟内调转到登录页面
  • 原文地址:https://www.cnblogs.com/haitaoli/p/10293378.html
Copyright © 2020-2023  润新知