• 序列化多表操作、请求与响应、视图组件(子类与拓展类)、继承GenericAPIView类重写接口


    今日内容概要

    • 序列化多表操作
    • 请求与相应
    • 视图组件

    内容详细

    1、序列化多表操作

    模型类 models.py中

    # 新建django项目
    # 创建表 模型类models.py中:
    from django.db import models
    
    # 4张表
    class Book(models.Model):
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # to='Publish' 自动关联publish表主键 // on_delete=models.CASCADE 级联删除
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
    
        @property
        def publish_detail(self):  # 定制字段
            return {'name': self.publish.name, 'addr': self.publish.city}
    
        @property
        def author_list(self):  # 定制字段
            l = []
            # print(self.authors.all())
            for author in self.authors.all():
                # print(author.author_detail)
                l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
            return l
        
        
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDatail', on_delete=models.CASCADE)
        # OneToOneField 就是 ForeignKey + unique=True
    
    
    class AuthorDatail(models.Model):
        telephone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
        
        
    """
    在每个表中写入数据一一对应
    第五个自动创建的关联表 也写入数据
    """
    

    image

    创建序列化类 serializer.py

    from .models import *
    from rest_framework import serializers
    
    
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = Book
            # fields = '__all__'
            fields = ['id', 'name', 'price', 'authors', 'publish', 'publish_detail', 'author_list']
    
            # 由于前端的publish与authors会显示为:id 所以需要定制序列化字段
            # depth=1  # 等同于定制序列化的字段(2种方案) 但是尽量不要用,因为它是关联表一层全部取出来
            # 定制序列化的字段(2种方案)选择表模型中: 显示出版社名、地址;作者名年龄地址
            extra_kwargs = {
                'publish': {'write_only': True},  # 原有的字段就不需要再显示
                'authors': {'write_only': True},
            }
    
    
    class AuthorSerializer(serializers.ModelSerializer):
        class Meta:
            model = Author
            fields = '__all__'
    
    
    class AuthorDetailSerialzier(serializers.ModelSerializer):
        class Meta:
            model = AuthorDatail
            fields = '__all__'
    
    
    class PublishSerialzier(serializers.ModelSerializer):
        class Meta:
            model = Publish
            fields = '__all__'
    

    视图类 views.py中:

    from .serializer import *
    from rest_framework.response import Response
    from rest_framework.views import APIView
    from app01.models import Book
    
    
    class BookView(APIView):
        # 查询所有图书
        def get(self, request):
            book_list = Book.objects.all()
            ser = BookSerializer(instance=book_list, many=True)
            return Response(ser.data)
    
        # 新增图书数据
        def post(self, request):
            ser = BookSerializer(data=request.data)
            if ser.is_valid():
                ser.save()
                return Response({"code": 100, 'msg': '新增成功', 'data': ser.data})
            return Response({"code": 101, 'msg': '新增失败', 'err': ser.errors})
    
    
    class BookDetailView(APIView):
    
        # 查询单条数据
        def get(self, request, pk):
            book = Book.objects.all().filter(pk=pk).first()
            ser = BookSerializer(instance=book)
            return Response(ser.data)
    
        # 修改数据
        def put(self, request, pk):
            book = Book.objects.all().filter(pk=pk).first()
            ser = BookSerializer(instance=book, data=request.data)
            if ser.is_valid():
                ser.save()
                return Response({"code": 100, 'msg': '修改成功', 'data': ser.data})
            return Response({"code": 101, 'msg': '修改出错', 'err': ser.errors})
    
        # 删除数据
        def delete(self, request, pk):
            Book.objects.filter(pk=pk).delete()
            return Response({"code": 100, 'msg': '删除成功'})
    

    路由 urls.py中:

    from django.contrib import admin
    from django.urls import path
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    
        path('books/', views.BookView.as_view()),
        path('books/<int:pk>', views.BookView.as_view()),
    ]
    

    image

    2、请求与相应

    2.1 请求

    # 请求就是指:Request 类的对象
    	>>> 新的request对象
        
    # 导入:
    	from rest_framework.request import Request
    
    # 需要记住的源码:
    	__getattr__
    	request.data
    	request.query_parmas--->self._request.GET
    		restful规范里,请求地址中带过滤(查询)条件
    		get请求地址中提交的数据在GET中,
    		query_parmas:查询参数
            
            
    # 了解
    	默认情况下,可以解析 urlencoded,formdata,json
        
        
    # 案例:
    	如果我们写了一个接口,想只能处理json格式,或者只能处理formdata
        
    1.局部配置 在views.py中:
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
    
    class PublishView(APIView):
        # 局部使用,只针对当前视图类有效
        # 只想处理json格式
        # parser_classes = [JSONParser,FormParser,MultiPartParser]  # 默认下 是处理三种格式数据
        parser_classes = [JSONParser]  # 只允许处理 JSONParser格式
    
        def post(self, request):
            print(request.data)
            return Response('post---publish')
    	
      
    2.全局配置-->要在配置文件中添加:
    # REST_FRAMEWORK  以后是drf的配置
    # 所有接口都只能解析json格式
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
        ],
    }
    
    3.全局配置解析json,局部某个视图函数想能解析formdata格式
    	视图类中配置一下即可 就是局部配置(按照使用顺序)
        
        
    # 如果局部配置如下,会怎么样
    	parser_classes = []  # 所有格式都补不能解析了
    
    # 使用顺序:
    	即使我们没有配置局部或者全局,也有默认配置:3个数据模式都能解析
        
    	视图类中配的(优先用)
    	项目配置文件的配置(其次)
    	drf有默认配置(最后)
    	
    	drf的默认配置:from rest_framework import settings
      
    
    # 总结:
    	一般情况下,都使用默认即可,不用配置(三种格式数据都能解析)
    

    image

    2.2 响应

    # 其实就是:Respone 返回给前端的
    
    # 导入:
    	from rest_framework.response import Response
        
    # 源码分析
    1.属性:
    	data=None,  # 返回给前端的数据:可以是 字符串,字典,列表 就是给http响应body体中内容-->也可以是response对象中取出数据并 处理
        
    	status=None,  # 响应状态码:1xx,2xx,3xx,默认是200
    
    	headers=None,      # 响应头 字典
      
    	了解:
    		template_name=None,  # 模板名字(不用),用浏览器访问时,可以改
    		exception=False,    # 异常处理
    		content_type=None   # 响应编码格式
            
        
    	from rest_framework.status import HTTP_201_CREATED
    	Response(ser.data,status=HTTP_201_CREATED)
        
    2.响应格式 跟解析数据格式类似
    # 局部配置 在视图类 views.py中配置:
    from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
    class BookDetailView(APIView):
        renderer_classes = [JSONRenderer, ]
    
    # 全局设置 在配置文件中配置:
    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
            'rest_framework.renderers.JSONRenderer',  # json渲染器
            'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
        )
    }
    

    image

    3、视图组件

    # APIView  
    	from rest_framework.views import APIView
        
    	类属性 renderer_classes,parser_classes...
    	get方法,post方法,delete方法 写法跟之前的View一样,只不过request对象变成了新的request
    	比之前的View多了三大认证和全局异常处理
      
      
    # GenericAPIView  继承了APIView 但是多了属性和方法
    	from rest_framework.generics import GenericAPIView
        
    	属性(先记两个):
    		queryset = None
    		serializer_class = None
            
    	方法:
    		get_queryset
    		get_object
    		get_serializer
        
        
        
    # 5个视图扩展类(不是视图类,没有集成APIView,需要配合GenericAPIView)
    	from rest_framework.mixins import 
    		CreateModelMixin,
    		ListModelMixin,
    		DestroyModelMixin,
    		RetrieveModelMixin,
    		UpdateModelMixin
      
      
      
    # 9个视图子类 
    	from rest_framework.generics import 
    		CreateAPIView,
    		ListAPIView,
    		DestroyAPIView,
    		RetrieveAPIView,
    		UpdateAPIView,
    		ListCreateAPIView,
    		RetrieveUpdateAPIView,
    		RetrieveUpdateDestroyAPIView,
    		RetrieveDestroyAPIView
    
    
    # 视图集
    	from rest_framework.viewsets import 
    		# 两个视图类
    		ModelViewSet, ReadOnlyModelViewSet,
    		# 视图类
    		ViewSet, GenericViewSet,
    		# 魔法类
    		ViewSetMixin
    

    继承GenericAPIView 重写视图类

    # 添加路由:
        path('publishs/<int:pk>', views.PublishDetailView.as_view()),
        
        
    # 视图类复制过来并做修改:
    # 第一层:继承APIView写视图类
    
    # 第二层:继承GenericAPIView写视图类
    from rest_framework.generics import GenericAPIView
    
    class PublishView(GenericAPIView):
        queryset = Publish.objects.all()
        serializer_class = PublishSerialzier
    
        # 查询所有图书
        def get(self, request):
            # obj = self.queryset
            obj = self.get_queryset()  # 等同于上面,obj = self.queryset 并且更好一些
    
            # ser = self.serializers(instance=obj, many=True)
            # ser=self.get_serializer_class()(instance=obj,many=True) # 等同于上面
            ser = self.get_serializer(instance=obj, many=True)  # 等同于上面
            return Response(ser.data)
    
        # 新增图书数据
        def post(self, request):
            # ser = BookSerializer(data=request.data)
            ser = self.get_serializer(data=request.data)  # 等同于上面
            if ser.is_valid():
                ser.save()
                return Response({"code": 100, 'msg': '新增成功', 'data': ser.data})
            return Response({"code": 101, 'msg': '新增失败', 'err': ser.errors})
    
    
    class PublishDetailView(GenericAPIView):
        queryset = Publish.objects.all()
        serializer_class = PublishSerialzier
    
        # 查询单条数据
        def get(self, request, *args, **kwargs):
            # book = Book.objects.all().filter(pk=pk).first()
            obj = self.get_object()  # 等同于上面
    
            # ser = BookSerializer(instance=book)
            ser = self.get_serializer(instance=obj)  # 等同于上面
            return Response(ser.data)
    
        # 修改数据
        def put(self, request, *args, **kwargs):
            # book = Book.objects.all().filter(pk=pk).first()
            obj = self.get_object()  # 等同于上面
    
            # ser = BookSerializer(instance=book, data=request.data)
            ser = self.get_serializer(instance=obj, data=request.data)  # 等同于上面
            if ser.is_valid():
                ser.save()
                return Response({"code": 100, 'msg': '修改成功', 'data': ser.data})
            return Response({"code": 101, 'msg': '修改出错', 'err': ser.errors})
    
        # 删除数据
        def delete(self, request, *args, **kwargs):
            # Book.objects.filter(pk=pk).delete()
            self.get_object().delete()
            return Response({"code": 100, 'msg': '删除成功'})
    

    image

    4、通过GenericAPIView + 5个视图扩展类 重写视图类

    # 第三层:GenericAPIView+5个视图扩展类 重写视图类
    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import CreateModelMixin, ListModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin
    
    class PublishView(GenericAPIView, CreateModelMixin, ListModelMixin):
        queryset = Publish.objects.all()
        serializer_class = PublishSerialzier
    
        # 查询所有图书
        def get(self, request):
            return super().list(request)  # list(request)ListModelMixin的方法
    
        # 新增图书数据
        def post(self, request):
            return super().list(request)  # create(request)ListModelMixin的方法
    
    
    class PublishDetailView(GenericAPIView, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
        queryset = Publish.objects.all()
        serializer_class = PublishSerialzier
    
        # 查询单条数据
        def get(self, request, *args, **kwargs):
            return super().retrieve(request, *args, **kwargs)
    
        # 修改数据
        def put(self, request, *args, **kwargs):
            return super().update(request, *args, **kwargs)
    
        # 删除数据
        def delete(self, request, *args, **kwargs):
            return super().destroy(request, *args, **kwargs)
    

    image

  • 相关阅读:
    d3js 实现水球图
    虚拟线程 - VirtualThread源码透视
    系统架构设计高级技能 · 构件与中间件技术
    文件夹直接打开:右键菜单,使用指定【工具】打开文件和文件夹 (通过IDEA/VScode打开)
    操作系统:存储器管理 练习题(带有详细答案解析)
    Linux学习——网络编程基础及TCP服务器
    数据源报表
    CAS SSO单点登录服务端环境搭建
    移动端JDtoolbar
    OpenLayers-要素属性信息简单弹窗
  • 原文地址:https://www.cnblogs.com/jgx0/p/16084437.html