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

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

1.1 序列化类

from rest_framework import serializers
from .models import Book, Publish, Author, AuthorDetail


# class BookSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = Book
#         fields = ['id', 'title', 'price', 'publish', 'authors', 'publish_detail',
#                   'author_detail']  # 字段可以是属性,也可以是方法(是方法返回值)
#         # depth=1  # 深度查一层,官方建议不大于10,正常不超过3,不建议用
#         extra_kwargs = {'publish': {'write_only': True},
#                         'authors': {'write_only': True},
#                         'publish_detail': {'read_only': True},
#                         'author_detail': {'read_only': True}
#                         }
#     # 把publish显示出版社的名字和地址
#     # 方式一:在表模型中写方法,在序列化类的fields声明一下就可以
#     # 方法二:在序列化类中写
# class BookSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = Book
#         # 写在BookSerializer的类属性,也需要在fields中注册一下
#         fields = ['id', 'title', 'price', 'publish', 'authors', 'publish_detail',
#                   'author_detail']  # 字段可以是属性,也可以是方法(是方法返回值)
#         # depth=1  # 深度查一层,官方建议不大于10,正常不超过3,不建议用
#         extra_kwargs = {'publish': {'write_only': True},
#                         'authors': {'write_only': True},
#                         }
#
#     # 把publish显示出版社的名字和地址
#     # 方式一:在表模型中写方法,在序列化类的fields声明一下就可以
#     # 方法二:在序列化类中写
#     publish_detail = serializers.SerializerMethodField(
#         read_only=True)  # 这个字段需要配合一个方法,方法必须叫get_字段名,方法返回什么,publish_detail就是什么
#
#     def get_publish_detail(self, obj):
#         # obj就是当前序列化到的对象,就是book对象
#         return {'name': obj.publish.name, 'address': obj.publish.address}
#
#     author_detail = serializers.SerializerMethodField(read_only=True)
#
#     def get_author_detail(self, obj):
#         author_list = obj.authors.all()
#         author_dict_list = []
#         for author in author_list:
#             author_dict_list.append({'name': author.name, 'sex': author.get_sex_display()})
#         return author_dict_list

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        # fields = ['id']
        fields = '__all__'


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


class AuthorDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = AuthorDetail
        fields = "__all__"


class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)  # 多条,一定要加一个 many=True
    class Meta:
        model = Book
        # 写在BookSerializer的类属性,也需要在fields中注册一下
        fields = ['id', 'title', 'price', 'publish', 'authors']  # 字段可以是属性,也可以是方法(是方法返回值)
        # depth=1  # 深度查一层,官方建议不大于10,正常不超过3,不建议用
        extra_kwargs = {'publish': {'write_only': True},
                        'authors': {'write_only': True},
                        }

    # 把publish显示出版社的名字和地址
    # 方式一:在表模型中写方法,在序列化类的fields声明一下就可以
    # 方法二:在序列化类中写
    # 方式三:通过子序列化


1.2 视图

from .models import Book, AuthorDetail, Author
from .seriazlizer import BookSerializer


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

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
        # ser.is_valid(raise_exception=True)


class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.all().filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(data=ser.data)

    def put(self, request, pk):
        book = Book.objects.all().filter(pk=pk).first()  # 数据不存在,None,如果instance是None,ser.save-->新增

        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

    def delete(self, request, pk):
        res = Book.objects.all().filter(pk=pk).delete()  # 返回影响的行数的元组
        print(res)  #
        if res[0] >= 1:
            return Response()
        else:
            return Response('要删除的数据不存在')

1.3 模型层

from django.db import models


# 图书表    出版社   作者  作者详情    图书和作者的多对多表

#
# 一对多:关系一旦确立,关联字段写在多的一方
# 多对多:需要有中间表


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 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')

    # @property  # 加不加都行
    # def publish_detail(self):
    #     return {'name': self.publish.name, 'address': self.publish.address}
    #
    # # 作者详情 在列表套字典
    # def author_detail(self):
    #     # 获取所有作者
    #     author_list = self.authors.all()
    #     author_dict_list = []
    #     for author in author_list:
    #         author_dict_list.append({'name': author.name, 'sex': author.get_sex_display()})
    #     return author_dict_list


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


class Author(models.Model):
    name = models.CharField(max_length=16)
    sex = models.IntegerField(choices=[(0, '男'), (1, '女')], default=0)


class AuthorDetail(models.Model):
    mobile = models.CharField(max_length=11)
    # OneToOneField 本质就是  ForeignKey+unique
    author = models.OneToOneField(to='Author', on_delete=models.CASCADE)
    # author = models.ForeignKey(to='Author', on_delete=models.CASCADE,unique=True)

1.4 路由

urlpatterns = [
    #    path('admin/', admin.site.urls),
    path('publish/', views.PublishView.as_view()),
    path('publish/<int:pk>', views.PublishDetailView.as_view()),
    path('book/', views.BookView.as_view()),
    path('book/<int:pk>', views.BookDetailView.as_view()),
]

2 请求与响应

2.1 Request

# 属性:
request.data  # 基于django中的request进行的二次封装,可以从request.data获取所有的数据
request.query_params
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
    )
}

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

2.1 响应 Response

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

#默认用浏览器可以看到页面,用postman可以看到jon
#只能显示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.mixins import RetrieveModelMixin,ListModelMixin,CreateModelMixin
class PublishView(GenericAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer


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

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
        # ser.is_valid(raise_exception=True)


class PublishDetailView(GenericAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def get(self, request, pk):
        obj = self.get_object()  # 获取单条,根据pk
        ser = PublishSerializer(instance=obj)
        return Response(data=ser.data)

    def put(self, request, pk):
        obj = self.get_object()  # 数据不存在,None,如果instance是None,ser.save-->新增

        ser = self.get_serializer(data=request.data, instance=obj)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

    def delete(self, request, pk):
        res = self.get_object().delete()  # 返回影响的行数的元组
        print(res)  #
        if res[0] >= 1:
            return Response()
        else:
            return Response('要删除的数据不存在')

上一篇:多图|一文详解Nacos参数!


下一篇:物联网项目-物美智能系统搭建