DRF.多表关联的序列化和反序列化、视图组件、请求与响应

DRF.多表关联的序列化和反序列化、视图组件、请求与响应

 


1.多表关联的序列化和反序列化

1.1模型层 models

Charfield   vaarchar   变长(给32长度 最多32,达不到 有多少占多少)   
char 定长(给32长度,如果只有一个字符 剩下的空格填充)

from django.db import models


# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField()
    # on_delete:
    # models.CASCADE  # 级联删除
    # models.DO_NOTHING # 什么都不做
    # models.SET_DEFAULT #设置为默认值
    # models.SET_NULL    # 设置为空
    # models.SET         #可以写一个函数内存地址,删除的时候,触发这个函数执行
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
    authors = models.ManyToManyField(to='Author',
                                     through='AuthorAndBook',
                                     through_fields=('book', 'author'))

    # @property  # 加不加都可以    self是book对象
    # def publish_detail(self):  # 获取publish对象 外键在自己这 点外键名.属性值
    #     return {'name':self.publish.name,'address':self.publish.address}
    #
    # @property
    # def authors_detail(self):
    #     # 因为多对多关系  有多个作者对象 所以要获取一下
    #     author_list = self.authors.all()
    #     author_list_obj = []
    #     for author in author_list:
    #         author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
    #     return author_list_obj


class AuthorAndBook(models.Model):
    book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
    author = models.ForeignKey(to='Author', on_delete=models.CASCADE)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    address = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=32)
    gender = models.IntegerField(choices=[(1, '男'), (2, '女')], default=1)
    detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    address = models.CharField(max_length=128)

让books显示作者信息和出版社信息的三种方式

第一种方式(在表模型写models)

 #写在book表里
    
    @property  # 加不加都可以    self是book对象
    def publish_detail(self):  # 获取publish对象 外键在自己这 点外键名.属性值
        return {'name':self.publish.name,'address':self.publish.address}

    @property
    def authors_detail(self):
        # 因为多对多关系  有多个作者对象 所以要获取一下
        author_list = self.authors.all()
        author_list_obj = []
        for author in author_list:
            author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
        return author_list_obj
    
    
#最后在serializer里的fileds注册一下
class BookSerializer(ModelSerializer):
    class Meta:
        model = models.Book
        # fields = '__all__'
        fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
        extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
                        'publish': {'write_only': True},
                        'publish_detail':{'read_only':True},
                        'authors_detail':{'read_only':True},
                        # 'authors': {'write_only': True},   #注释是因为第三张表如果手动创建 会有问题

第二种方式(在序列化类中写)

#主要用SerializerMethodField方法名必须配合一个get_方法名的方法

#相当于把方法写在序列化类里  也要去fields注册
        #第二种方法
        fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
        extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
                        'publish': {'write_only': True},
                        'publish_detail':{'read_only':True},
                        'authors_detail':{'read_only':True},
                        # 'authors': {'write_only': True},#注释是因为第三张表如果手动创建 会有问题
                        }
        #@property  # 加不加都可以    self是book对象 和class Meta平级
    publish_detail=serializers.SerializerMethodField(read_only=True) #这个字段必须配合这个名字前加get的方法 方法返回什么 他就是什么
    def get_publish_detail(self,obj):  # 获取publish对象 外键在自己这 点外键名.属性值
        #obj就是要序列化的对象 当前book对象
        return {'name':obj.publish.name,'address':obj.publish.address}

    authors_detail = serializers.SerializerMethodField(read_only=True)
    #@property
    def get_authors_detail(self,obj):
        # 因为多对多关系  有多个作者对象 所以要获取一下
        author_list = obj.authors.all()
        author_list_obj = []
        for author in author_list:
            author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
        return author_list_obj

第三种方式(通过子序列化)

		#第三种方式
        fields = ['title', 'price', 'publish', 'authors']
        extra_kwargs = {'title': {'max_length': 8, 'min_length': 3}, }
    publish = PublishSerializer() #直接调用那个序列化类 重新赋值给publish
    authors = AuthorSerializer(many=True) #直接调用那个序列化类 重新赋值给authors 多条要加many=true

view视图层

from django.shortcuts import render

# Create your views here.
from rest_framework.views import APIView
from app01 import models
from app01.myserializer import BookSerializer
from rest_framework.response import Response


class Book(APIView):
    def get(self, request):
        book_list = models.Book.objects.all()
        bs = BookSerializer(instance=book_list, many=True)
        return Response(data=bs.data)



    def post(self, request):
        bs = BookSerializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(data=bs.data)
        else:
            return Response(data=bs.errors)


class BookDetail(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        bs = BookSerializer(instance=book_obj)
        return Response(data=bs.data)

    def put(self,request,pk):
        book_obj=models.Book.objects.filter(pk=pk).first()
        # 数据不存在,None,如果instance是None,ser.save-->新增
        bs=BookSerializer(instance=book_obj,data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)


    def delete(self,request,pk):
        bs=models.Book.objects.filter(pk=pk).delete()

        return Response()

#Publish 五个接口
from .myserializer import PublishSerializer
class Publish(APIView):
    def get(self, request):
        book_list = models.Publish.objects.all()
        bs = PublishSerializer(instance=book_list, many=True)
        return Response(data=bs.data)

    def post(self, request):
        bs = PublishSerializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(data=bs.data)
        else:
            return Response(data=bs.errors)


class PublishDetail(APIView):
    def get(self, request, pk):
        book_obj = models.Publish.objects.filter(pk=pk).first()
        bs = PublishSerializer(instance=book_obj)
        return Response(data=bs.data)

    def put(self,request,pk):
        book_obj=models.Publish.objects.filter(pk=pk).first()
        # 数据不存在,None,如果instance是None,ser.save-->新增
        bs=PublishSerializer(instance=book_obj,data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)


    def delete(self,request,pk):
        bs=models.Publish.objects.filter(pk=pk).delete()

        return Response()

Serializer

from app01 import models
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from rest_framework.exceptions import ValidationError


class PublishSerializer(ModelSerializer):
    class Meta:
        model = models.Publish
        fields = '__all__'


class AuthorSerializer(ModelSerializer):
    class Meta:
        model = models.Author
        fields = '__all__'


class BookSerializer(ModelSerializer):
    class Meta:
        model = models.Book
        # 让book表显示出版社信息和用户信息
        # 第一种方法
        # fields = '__all__'
        # fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
        # extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
        #                 'publish': {'write_only': True},
        #                 'publish_detail':{'read_only':True},
        #                 'authors_detail':{'read_only':True},
        #                 # 'authors': {'write_only': True},
        #                 }

        # depth = 1  # 深度查一层,官方建议不大于10,正常不超过3,不建议用

        # 第二种方法
        #     fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
        #     extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
        #                     'publish': {'write_only': True},
        #                     'publish_detail':{'read_only':True},
        #                     'authors_detail':{'read_only':True},
        #                     # 'authors': {'write_only': True},
        #                     }
        #     #@property  # 加不加都可以    self是book对象
        # publish_detail=serializers.SerializerMethodField(read_only=True)
        # def get_publish_detail(self,obj):  # 获取publish对象 外键在自己这 点外键名.属性值
        #     return {'name':obj.publish.name,'address':obj.publish.address}
        #
        # authors_detail = serializers.SerializerMethodField(read_only=True)
        # #@property
        # def get_authors_detail(self,obj):
        #     # 因为多对多关系  有多个作者对象 所以要获取一下
        #     author_list = obj.authors.all()
        #     author_list_obj = []
        #     for author in author_list:
        #         author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
        #     return author_list_obj

        #     第三种方式
        fields = ['title', 'price', 'publish', 'authors']
        extra_kwargs = {'title': {'max_length': 8, 'min_length': 3}, }

    publish = PublishSerializer() #直接调用那个序列化类 重新赋值给publish
    authors = AuthorSerializer(many=True) #直接调用那个序列化类 重新赋值给authors

    def validate_title(self, title):
        if title.startswith('lv'):
            raise ValidationError('书名不能以lv开头')
        return title

    def validate(self, attrs):
        if attrs.get('title') == attrs.get('publish__name'):
            raise ValidationError('书名不能和出版社相同')
        return attrs

urls

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/',views.Book.as_view()),
    path('books/<int:pk>/',views.BookDetail.as_view()),
    path('publish/',views.Publish.as_view()),
    path('publish/<int:pk>/',views.PublishDetail.as_view()),
]

2.请求与响应

2.1Request

#REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
#######Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。
#无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

# 属性:
request.data #返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,
	#但提供如下特性:
    包含了解析之后的文件和非文件数据
    包含了对POST、PUT、PATCH请求方式解析后的数据
    利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
request.query_params# 与Django标准的request.GET相同,只是更换了更正确的名称而已
	
request._request  原来的request
request.method  --->就是使用了原来的request的method  通过重写 __getattr__魔法方法实现的

# 默认情况下post提交数据,可以三种方式(form-data,urlencoded,json),都能处理
# 我们只允许接口接收json格式,其他格式不支持
# 方式一:全局配置,在配置文件中
REST_FRAMEWORK = {
    # 默认能够解析的编码方式
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',  # json的
        # 'rest_framework.parsers.FormParser', # urlencoded
        # 'rest_framework.parsers.MultiPartParser' # form-data
    )
}

# 局部配置:(视图类)
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class PublishView(APIView):
    parser_classes = [FormParser,]  # 优先级更高
    
    
 # 优先级:先用视图类自己的,再用配置文件---》drf的默认配置

2.2响应Response

# 属性:
data:返回给前端的数据,可以是字典,列表,字符串
status:响应状态码,1xx 2xx 3xx 4xx 5xx
template_name : 不用,替换模板
headers=None  :响应头

#默认用浏览器可以看到页面,用postman可以看到json
#只能显示json
# 方式一:全局配置,在配置文件中
REST_FRAMEWORK = {
    # 使用的渲染类
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        # 'rest_framework.renderers.BrowsableAPIRenderer',
    )
}

# 局部配置:(视图类)
class PublishView(APIView):
    renderer_classes = [JSONRenderer,]

 # 优先级:先用视图类自己的,再用配置文件---》drf的默认配置
    

3.视图组件

3.1 两个视图基类

##### 通过继承GenericAPIView 写5个接口
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView  # 继承APIView,写了几个类属性
'''
# 类属性
queryset = None  #  指明使用的数据查询集 所有数据 或者
serializer_class = None #  指明视图使用的序列化器
lookup_field = 'pk'  # 查询单条转换器的字段

# 三个方法
self.get_queryset()   # 获取所有数据
self.get_serializer   # 获取序列化类
self.get_object()    # 获取单条数据  一般用在查询单条数据  修改数据 删除单条数据等
'''


#快速写五个接口
from rest_framework.generics import GenericAPIView
class Publish(GenericAPIView):
    queryset = models.Publish.objects.all()
    serializer_class = PublishSerializer


    def get(self, request):
        obj = self.get_queryset()
        bs = self.get_serializer(instance=obj, many=True)
        return Response(data=bs.data)

    def post(self, request):
        bs = self.get_serializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(data=bs.data)
        else:
            return Response(data=bs.errors)

class PublishDetail(GenericAPIView):
    queryset = models.Publish.objects.all()
    serializer_class = PublishSerializer
    # lookup_field = 'pk'   如果不是传过来的值不是pk ,改他 根据pk筛选
    def get(self, request, pk):
        obj = self.get_object()
        bs = self.get_serializer(instance=obj)
        return Response(data=bs.data)

    def put(self,request,pk):
        obj=self.get_object()
        # 数据不存在,None,如果instance是None,ser.save-->新增
        bs=self.get_serializer(instance=obj,data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)


    def delete(self,request,pk):
        bs=self.get_object().delete()
        print(bs)
        if bs[0] >= 1:
            return Response()
        else:
            return Response('要删除的数据不存在')

 

封装第一层

#封装第一层 views视图函数
# 封装版本第一版
from rest_framework.generics import GenericAPIView
from app01.customclass import NewPublish


class Publish(GenericAPIView):
    queryset = models.Publish.objects.all()
    serializer_class = PublishSerializer

    def get(self, request):
        return NewPublish.getpublishlist(self)

    def post(self, request):
        return NewPublish.createpublishobj(self,request)


class PublishDetail(GenericAPIView):
    queryset = models.Publish.objects.all()
    serializer_class = PublishSerializer
    def get(self, request, pk):

        return NewPublish.getpublishobj(self)

    def put(self, request, pk):
        return NewPublish.putpublishobj(self,request)

    def delete(self, request, pk):
        return NewPublish.depublishobj(self)

    #封装的类
    from rest_framework.response import Response


class NewPublish:
    def getpublishlist(self, *args, **kwargs):
        obj = self.get_queryset()
        bs = self.get_serializer(instance=obj, many=True)
        return Response(bs.data)

    def getpublishobj(self, *args, **kwargs):
        obj = self.get_object()
        bs = self.get_serializer(instance=obj)
        return Response(bs.data)

    def putpublishobj(self, request, *args, **kwargs):
        obj = self.get_object()
        # 数据不存在,None,如果instance是None,ser.save-->新增
        bs = self.get_serializer(instance=obj, data=request.data)
        bs.is_valid(raise_exception=True)
        bs.save()
        return Response(bs.data)

    def createpublishobj(self, request, *args, **kwargs):
        bs = self.get_serializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(data=bs.data)
        else:
            return Response(data=bs.errors)

    def depublishobj(self, *args, **kwargs):
        bs = self.get_object().delete()
        if bs[0] >= 1:
            return Response()
        else:
            return Response('要删除的数据不存在')
from rest_framework.response import Response


class NewPublish:
    def getpublishlist(self,*args,**kwargs):
        obj = self.get_queryset()
        bs = self.get_serializer(instance=obj, many=True)
        return Response(bs.data)

    def getpublishobj(self,*args,**kwargs):
        obj = self.get_object()
        bs = self.get_serializer(instance=obj)
        return Response(bs.data)

    def putpublishobj(self,request,*args,**kwargs):
        obj = self.get_object()
        # 数据不存在,None,如果instance是None,ser.save-->新增
        bs = self.get_serializer(instance=obj, data=request.data)
        bs.is_valid(raise_exception=True)
        bs.save()
        return Response(bs.data)


    def createpublishobj(self,request,*args,**kwargs):
        bs = self.get_serializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(data=bs.data)
        else:
            return Response(data=bs.errors)

    def depublishobj(self,*args,**kwargs):
        bs = self.get_object().delete()
        if bs[0] >= 1:
            return Response()
        else:
            return Response('要删除的数据不存在')

 



posted @ 2021-12-23 14:32  迪迦张  阅读(307)  评论(0编辑  收藏  举报