DRF~day04 之序列化高级用法之source、序列化高级用法之定制字段的两种方式、多表关联反序列化保存、反序列化字段校验其他、ModelSerializer使用

DRF 之 序列化高级用法之source、 序列化高级用法之定制字段的两种方式、多表关联反序列化保存、反序列化字段校验其他、ModelSerializer使用



一、 序列化高级用法之source

1.1、 创建表模型(models.py文件下创建)

from django.db import models

# Create your models here.


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    # on_delete:
    # CASCADE:级联删除,只要删除publish,跟publish关联的book,全都被删除
    # SET_DEFAULT:只要删除publish,跟publish关联的book,的publish字段会变成默认值,一定要配合default使用
    # SET_NULL:只要删除publish,跟publish关联的book,的publish字段会变成空,一定要配合null=True使用
    # models.SET(add):括号中可以放个值,也可以放个函数内存地址,只要删除publish,跟publish关联的book,的publish字段会变成set设的值或执行函数
    # 书籍和出版社是 : 1对多关系 ForeignKey(to='表名', )
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
    # 多对多关系
    authors = models.ManyToManyField(to='Author')

    # source的第二种用法 : 给查询数来的书籍名添加后缀名
    def sb_name(self):
        return self.name + '_sb'

    # 定义字段类型的方式2:
    # 字典类型
    # @property 的意思是把方法变成可以调用的数据(可加可不加)
    @property
    def publish_dict(self):
        # 这个对象是
        return {'id': self.publish.pk, 'name': self.publish.name, 'addr': self.publish.addr}

    def author_list(self):
        l =[]
        for list in self.authors.all():
            l.append({'id': list.pk, 'name': list.name, 'phone': list.phone, 'age': list.author_detail.age})
        return l


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


class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=11)
    # 本质就是ForeignKey,但是唯一,多的一方唯一,形成了一对一
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    email = models.CharField(max_length=32)
    age = models.IntegerField()

1.2、路由设置

    path('book/', views.bookview.as_view()),
    path('book/<int:pk>/', views.BookDetailView.as_view()),

1.3、视图类代码

class bookview(APIView):
    def get(self, request):
        res = models.Book.objects.all()
        # 把查询的表的对象res传入到序列化类中进行数据处理,在Bookserializers()的括号中用instance接收对象
        ser = Bookserializers(instance=res, many=True)
        print(res)
        print(ser.data)
        return Response({'code': 200, 'msg': '成功', 'results': ser.data})

    def post(self, request):
        # 创建数据
        # 接收前端传来的数据去反序列化
        print(request.data)
        res = Bookserializers(data=request.data)  # 反序列化
        # 校验反序列化后的数据
        if res.is_valid():
            print(res.validated_data)  # 打印校验之后的数据
            # 保存数据
            res.save()
            return Response({'code': 200, 'msg': '更新成功'})
        else:
            print(res.errors)  # 打印校验失败的信息
            return Response({'code': 404, 'msg': '创建失败', '失败data': res.errors})


class BookDetailView(APIView):
    # 查询单个数据
    def get(self, request, pk):
        res_obj = models.Book.objects.all().get(pk=pk)
        ser = Bookserializers(res_obj)  # 序列化
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    # 修改数据
    def put(self, request, pk):
        res_obj = models.Book.objects.filter(pk=pk).first()
        print(res_obj)
        ser = Bookserializers(instance=res_obj, data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'results': ser.validated_data})
        else:
            print(ser.validated_data)
            return Response({'code': 100, 'msg': '修改失败', 'results': ser.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).first().delete()
        return Response({'code': 100, 'msg': '删除成功'})

1.4、序列化类代码

# 1、 source的用法
class Bookserializers(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    # 写的这些字段类的名字,必须是book对象中的属性,不然book_name会报错
    # 如果不想报错,使用source指定book对象中的属性
    # 第一种用法:放一个对象的属性
    # book_name = serializers.CharField(source='name')  # 给前端看到的是 book_name
    # name = serializers.CharField(source='name')  # 坑,会报错
    # name = serializers.CharField()  # 同一个字段,可以序列化多次,但一般不会写
    book_name = serializers.CharField(source='name')
    book_price = serializers.CharField(source='price')

    # # 第二种用法:放一个对象的方法  book.sb_name()--->真正的书名_sb
    # # 在模型表中写方法
    # # 这个方法的意思是: 给查询出来的数据添加一个_sb的后缀名
    # book_name = serializers.CharField(source='sb_name')
    # book_price = serializers.CharField(source='price')

    # # 第三种:关联查询,拿出出版社的名字
    # Publish_name = serializers.CharField(source='publish.name')
    #
    # name = serializers.CharField()
    # price = serializers.CharField()

1.5、source的用法的展示

1.5.1、用法一:展示数据信息

  • 普通展示
    在这里插入图片描述
  • 使用source的方法展示(自定义字段展示给前端看)
    在这里插入图片描述

1.5.2、用法二:给查询出来的数据添加一个_sb的后缀名

  • 序列化类中的代码
    # # 第二种用法:放一个对象的方法  book.sb_name()--->真正的书名_sb
    # # 在模型表中写方法
    # # 这个方法的意思是: 给查询出来的数据添加一个_sb的后缀名
    book_name = serializers.CharField(source='sb_name')
    book_price = serializers.CharField(source='price')
  • 模型层中的代码
    # source的第二种用法 : 给查询数来的书籍名添加后缀名
    def sb_name(self):
        return self.name + '_sb'
  • 展示效果
    在这里插入图片描述

1.5.3、用法三:关联查询,拿出出版社的名字:

  • 序列化类中的代码
    # # 第三种:关联查询,拿出出版社的名字
    # 这里的source='publish.name'是跨表查询出版社表中对应的出版社名称
    Publish_name = serializers.CharField(source='publish.name')
    name = serializers.CharField()
    price = serializers.CharField()
  • 展示效果
    在这里插入图片描述

1.6 总结

# 总结:1、source的用法
	-1 修改前端看到的字段key值---》source指定的必须是对象的属性
    	book_name = serializers.CharField(source='name')
    -2 修改前端看到的value值,---》source指定的必须是对象的方法
    	表模型中写方法
          def sb_name(self):
        	return self.name + '_sb'
        序列化类中
        	book_name = serializers.CharField(source='sb_name')
            
     -3 可以关联查询(得有关联关系)
    	publish_name = serializers.CharField(source='publish.name')
    

# 2 定制序列化的字段之source,字段参数
	- 指定一个要序列化的对象中得字段
    - 指定一个要序列化的对象中得方法,方法返回什么,字段就是什么
    - 指定连表操作

二、序列化高级用法之定制字段的两种方式

2.1、方式一:在序列化类中写方法


方式一:在序列化类中写
	1 写一个字段,对应的字段类是:SerializerMethodField
    2 必须对应一个 get_字段名的方法,方法必须接受一个obj,返回什么,这个字段对应的value就是什么
  • 序列化类中的代码
# 2、 定制字段方式1
class Bookserializers(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    # 拿出出版社的id和名字和addr,放到一个字典中
    # 方式一:SerializerMethodField来定制,
    # 如果写了这个,必须配合一个方法get_字段名,这个方法返回什么,这个字段的值就是什么
    publish_dict = serializers.SerializerMethodField()

    # 这个字段名必须是 SerializerMethodField() 的字段
    # 返回的字段要自己定义

    def get_publish_dict(self, obj):
        # 这个obj变量是随便写的,因为这个变量是视图类传进来的对象,
        # 把instance接收对象写到get_字段名 的方法的形参中
        print(obj)
        return {'id': obj.publish.pk, 'name': obj.publish.name, 'addr': obj.publish.addr}

    # 练习:拿出所有作者的信息--》多条 [{name:,phone:},{}] 列表样式
    author_list = serializers.SerializerMethodField()

    def get_author_list(self, lili):
        print(lili)
        lk = []
        for i in lili.authors.all():
            lk.append({'id': i.pk, 'name': i.name, 'phone': i.phone, 'age': i.author_detail.age})
        return lk

效果展示
在这里插入图片描述

2.2、方式二:在模型类中写方法

  • 序列化中的代码
# 2、 定制字段方式2
class Bookserializers(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    # # 1 序列化类中这样写
    # # 2 到表模型中写一个方法,方法名必须叫 publish_dict,这个方法返回什么,这个字段的value就是什么
    # # DictField() 字典类型
    publish_dict = serializers.DictField()

    # ListField()列表类型
    author_list = serializers.ListField()
  • 模型层中的代码
    # 定义字段类型的方式2:
    # 字典类型
    # @property 的意思是把方法变成可以调用的数据(可加可不加)
    @property
    def publish_dict(self):
        # 这个对象是
        return {'id': self.publish.pk, 'name': self.publish.name, 'addr': self.publish.addr}

    def author_list(self):
        l =[]
        for list in self.authors.all():
            l.append({'id': list.pk, 'name': list.name, 'phone': list.phone, 'age': list.author_detail.age})
        return l

展示效果
在这里插入图片描述

2.3、总结

# 定制序列化的字段之  两种方式(为了关联查询)
	-方式一:
        -在序列化类中写  SerializerMethodField---》get_字段名(self,obj),返回什么这个字段就是什么
        -基于对象的跨表查询
            -正向:book.publish
            -反向:publish.book_set.all()
            
    -方式二:
    	-在表模型中写方法,方法返回结果
        -在序列化类中,使用ListField,DictField...接收

三、多表关联反序列化保存和修改

# 序列化和反序列化,用的同一个序列化类
	-序列化的字段有:name,price ,   publish_detail,author_list
    -反序列化字段:name,price    ,publish,author

3.1 反序列化之保存

  • 视图类
class BookView(APIView):
    def post(self, request):
        ser = BookSerialzier(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

*序列化类

class Bookserializers(serializers.Serializer):
    # 即用来做序列化,又用来做反序列化
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 这俩,只用来做序列化
    # read_only参数 表明该字段仅用于序列化输出,默认False
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 这俩,只用来做反序列化
    # write_only参数 表明该字段仅用于反序列化输入,默认False
    publish_id = serializers.IntegerField(write_only=True)
    authors = serializers.ListField(write_only=True)

    # 局部钩子:给某个字段做个校验
    # 书名中不能包含sb
    # validate_字段名
    # def validate_name(self, name):
    #     pass

    # 创建表数据
    def create(self, validated_data):
        # 这里是接收前端传来的数据,数据在validated_data 里面
        # 创建数据表的数据,传来数据是字典类型
        # 正常这样写,但是这是多表操作,所以不行
        # book = Book.objects.create(name=validated_data.get('name'),
        #                            price=validated_data.get('price'),
        #                            publish=validated_data.get('publish'),
        #                            authors=validated_data.get('authors')
        #                            )

        # 先操作书籍表
        # 但是数据里面有列表形式数据所有先删除数据拿返回值打散数据变成关键字参数进行传递
        authors = validated_data.pop('authors')
        # 数据在validated_data 里面是关键字的形式所有用**kwargs接收
        book = Book.objects.create(**validated_data)
        # 这样原先的author的数据是[1,2],后面数据是(1,2)使用*args接收
        # 书籍和作者表是多对多的关系,所以要块表操作,正向查询表名小写,添加数据
        book.authors.add(*authors)
        # 保存操作数据
        book.save()
        return book

  • 展示
    在这里插入图片描述

    在这里插入图片描述

3.2 反序列化之修改

  • 视图类
    # 修改数据
    def put(self, request, pk):
        res_obj = models.Book.objects.filter(pk=pk).first()
        print(res_obj)
        ser = Bookserializers(instance=res_obj, data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'results': ser.validated_data})
        else:
            print(ser.validated_data)
            return Response({'code': 100, 'msg': '修改失败', 'results': ser.errors})
  • 序列化类
#### 3 序列化类,即做序列化,又做反序列化,还做数据校验
class Bookserializers(serializers.Serializer):
    # 即用来做序列化,又用来做反序列化
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 这俩,只用来做序列化
    # read_only参数 表明该字段仅用于序列化输出,默认False
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 这俩,只用来做反序列化
    # write_only参数 表明该字段仅用于反序列化输入,默认False
    publish_id = serializers.IntegerField(write_only=True)
    authors = serializers.ListField(write_only=True)

    # 局部钩子:给某个字段做个校验
    # 书名中不能包含sb
    # validate_字段名
    # def validate_name(self, name):
    #     pass
    
	# 修改数据
    def update(self, instance, validated_data):
        # 数据里面有列表形式数据所有先删除数据拿返回值打散数据变成关键字参数进行传递
        authors = validated_data.pop('authors')
        # print(authors, type(authors))
        # authors = list(authors)
        # print(authors, type(authors))
        for intem in validated_data:  # 把字典进行循环
            # setattr反射方法: setatter(对象,属性,属性值)
            # 这个的意思是如果对象对应的属性和属性值就修改属性值,没有就新增属性和属性值
            setattr(instance, intem, validated_data[intem])
        # instance是视图函数查询出来的书籍表的对象,书籍表操作作者表相关联的表数据
        # 把第三张表数据操作
        instance.authors.set(authors)
        instance.save()
        return instance

展示
在这里插入图片描述

3.3、总结

#  反序列化的保存和修改
	-保存:book:{name:xx,price:18,publish_id:1,authors:[1]}
    -视图函数中:ser=BookSerializer(data=request.data)
    -ser.is_valid()---->校验过后的数据---》ser.validated_data
    -视图类中:ser.save()
    -序列化类中:重写 create方法--->自己写保存
    
    
    -修改:book:{name:xx,price:18,publish_id:1,authors:[1]}
    -视图函数中:ser=BookSerializer(data=request.data,instance=book)
     -ser.is_valid()---->校验过后的数据---》ser.validated_data
    -视图类中:ser.save()
    -序列化类中:重写 update方法--->自己写修改

四、反序列化字段校验其他

# 视图类中调用:ser.is_valid()---》触发数据的校验
	-4-字段自己的:max_length,required。。。
        -字段自己的:配合一个函数name = serializers.CharField(max_length=8,validators=[xxx])
        -局部钩子
        -全局钩子

五、ModelSerializer使用

# 5 ModelSerialzier的使用
'''
# 现在学的ModelSerializer,表示跟表模型一一对应,用法跟之前基本类似
1 写序列化类,继承ModelSerializer
2 在序列化类中,再写一个类,必须叫
    class Meta:
        model=表模型
         fields=[] # 要序列化的字段
3 可以重写字段,一定不要放在class Meta
    -定制字段,跟之前讲的一样
4 自定制的字段,一定要在fields中注册一下
5 class Meta: 有个extra_kwargs,为某个字段定制字段参数
6 局部钩子,全局钩子,完全一致
7 大部分请情况下,不需要重写 create和update了
'''

class Bookserializers(serializers.ModelSerializer):
    class Meta:
        model =Book   # 指定表模型 (相当于把book表中的所有东西复制一份到这里来了)
        # fields='__all__'  # 把表模型中所有字段都映射过来
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']  # 自定制的字段,一定要在这里注册一下
        extra_kwargs = {
            'name': {'max_length': 10, 'required': True},
            'publish': {'write_only': True},
            'authors': {'write_only': True}
        }

    # 自定制字段:publish_detail  author_list 写法有两种,跟之前一模一样
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)
  • 展示
    查看所有书籍信息
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

总结:

# 之前写的序列化类,继承了Serializer,写字段,跟表模型没有必然联系
class XXSerialzier(Serializer)
	id=serializer.CharField()
	name=serializer.CharField()
    
 XXSerialzier既能序列化Book,又能序列化Publish


# 现在学的ModelSerializer,表示跟表模型一一对应,用法跟之前基本类似

	1 写序列化类,继承ModelSerializer
    2 在序列化类中,再写一个类,必须叫
    	class Meta:
			model=表模型
             fields=[] # 要序列化的字段
             # fields=['id','自定制字段']  # 分析明白:哪些字段是读写,哪些字段是只读,哪些字段是只写
    		 extra_kwargs={'id':{'required':True,'write_only':True}}
    3 可以重写字段,一定不要放在class Meta
    book_name=serializer.CharField(source='name',read_only=True)
    	-定制字段,跟之前讲的一样
    4 自定制的字段,一定要在fields中注册一下
    5 class Meta: 有个extra_kwargs,为某个字段定制字段参数
    6 局部钩子,全局钩子,完全一致
    7 大部分请情况下,不需要重写 create和update了
    

六、总代码

  • 路由层
urlpatterns = [
    path('admin/', admin.site.urls),
    # 做路由分发
    path('app01/', include('app01.urls')),
]


# app01的路由

from django.urls import path
from app01 import views

urlpatterns = [
    path('book/', views.bookview.as_view()),
    path('book/<int:pk>/', views.BookDetailView.as_view()),

    path('publish/', views.Publishview.as_view()),
    path('publish/<int:pk>/', views.Publishviewkk.as_view()),

    path('author/', views.Authorview.as_view()),
    path('author/<int:pk>/', views.Authorviews.as_view()),

]

  • 模型层
from django.db import models

# Create your models here.


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    # on_delete:
    # CASCADE:级联删除,只要删除publish,跟publish关联的book,全都被删除
    # SET_DEFAULT:只要删除publish,跟publish关联的book,的publish字段会变成默认值,一定要配合default使用
    # SET_NULL:只要删除publish,跟publish关联的book,的publish字段会变成空,一定要配合null=True使用
    # models.SET(add):括号中可以放个值,也可以放个函数内存地址,只要删除publish,跟publish关联的book,的publish字段会变成set设的值或执行函数
    # 书籍和出版社是 : 1对多关系 ForeignKey(to='表名', )
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
    # 多对多关系
    authors = models.ManyToManyField(to='Author')

    # source的第二种用法 : 给查询数来的书籍名添加后缀名
    def sb_name(self):
        return self.name + '_sb'




    # 定义字段类型的方式2:
    # 字典类型
    # @property 的意思是把方法变成可以调用的数据(可加可不加)
    @property
    def publish_dict(self):
        # 这个对象是
        return {'id': self.publish.pk, 'name': self.publish.name, 'addr': self.publish.addr}

    def author_list(self):
        l =[]
        for list in self.authors.all():
            l.append({'id': list.pk, 'name': list.name, 'phone': list.phone, 'age': list.author_detail.age})
        return l


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


class Author(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=11)
    # 本质就是ForeignKey,但是唯一,多的一方唯一,形成了一对一
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    email = models.CharField(max_length=32)
    age = models.IntegerField()

  • 序列化类
from rest_framework import serializers
from .models import Book
# 局部钩子验证模块导入
from rest_framework.exceptions import ValidationError


# 1、 source的用法
# class Bookserializers(serializers.Serializer):
# name = serializers.CharField()
# price = serializers.CharField()
# 写的这些字段类的名字,必须是book对象中的属性,不然book_name会报错
# 如果不想报错,使用source指定book对象中的属性
# 第一种用法:放一个对象的属性
# book_name = serializers.CharField(source='name')  # 给前端看到的是 book_name
# name = serializers.CharField(source='name')  # 坑,会报错
# name = serializers.CharField()  # 同一个字段,可以序列化多次,但一般不会写
# book_name = serializers.CharField(source='name')
# book_price = serializers.CharField(source='price')

# # 第二种用法:放一个对象的方法  book.sb_name()--->真正的书名_sb
# # 在模型表中写方法
# # 这个方法的意思是: 给查询出来的数据添加一个_sb的后缀名
# book_name = serializers.CharField(source='sb_name')
# book_price = serializers.CharField(source='price')

# # 第三种:关联查询,拿出出版社的名字
# Publish_name = serializers.CharField(source='publish.name')
# name = serializers.CharField()
# price = serializers.CharField()


# # 2、 定制字段方式1
# class Bookserializers(serializers.Serializer):
#     name = serializers.CharField()
#     price = serializers.CharField()
#     # 拿出出版社的id和名字和addr,放到一个字典中
#     # 方式一:SerializerMethodField来定制,
#     # 如果写了这个,必须配合一个方法get_字段名,这个方法返回什么,这个字段的值就是什么
#     publish_dict = serializers.SerializerMethodField()
#
#     # 这个字段名必须是 SerializerMethodField() 的字段
#     # 返回的字段要自己定义
#
#     def get_publish_dict(self, obj):
#         # 这个obj变量是随便写的,因为这个变量是视图类传进来的对象,
#         # 把instance接收对象写到get_字段名 的方法的形参中
#         print(obj)
#         return {'id': obj.publish.pk, 'name': obj.publish.name, 'addr': obj.publish.addr}
#
#     # 练习:拿出所有作者的信息--》多条 [{name:,phone:},{}] 列表样式
#     author_list = serializers.SerializerMethodField()
#
#     def get_author_list(self, lili):
#         print(lili)
#         lk = []
#         for i in lili.authors.all():
#             lk.append({'id': i.pk, 'name': i.name, 'phone': i.phone, 'age': i.author_detail.age})
#         return lk


# # 2、 定制字段方式2
# class Bookserializers(serializers.Serializer):
#     name = serializers.CharField()
#     price = serializers.CharField()
#     # # 1 序列化类中这样写
#     # # 2 到表模型中写一个方法,方法名必须叫 publish_dict,这个方法返回什么,这个字段的value就是什么
#     # # DictField() 字典类型
#     publish_dict = serializers.DictField()
#
#     # ListField()列表类型
#     author_list = serializers.ListField()


# #### 3 序列化类,即做序列化,又做反序列化,还做数据校验
# class Bookserializers(serializers.Serializer):
#     # 即用来做序列化,又用来做反序列化
#     name = serializers.CharField(max_length=8)
#     price = serializers.CharField()
#
#     # 这俩,只用来做序列化
#     # read_only参数 表明该字段仅用于序列化输出,默认False
#     publish_detail = serializers.DictField(read_only=True)
#     author_list = serializers.ListField(read_only=True)
#
#     # 这俩,只用来做反序列化
#     # write_only参数 表明该字段仅用于反序列化输入,默认False
#     publish_id = serializers.IntegerField(write_only=True)
#     authors = serializers.ListField(write_only=True)
#
#     # 局部钩子:给某个字段做个校验
#     # 书名中不能包含sb
#     # validate_字段名
#     # def validate_name(self, name):
#     #     pass
#
#     # 创建表数据
#     def create(self, validated_data):
#         # 这里是接收前端传来的数据,数据在validated_data 里面
#         # 创建数据表的数据,传来数据是字典类型
#         # 正常这样写,但是这是多表操作,所以不行
#         # book = Book.objects.create(name=validated_data.get('name'),
#         #                            price=validated_data.get('price'),
#         #                            publish=validated_data.get('publish'),
#         #                            authors=validated_data.get('authors')
#         #                            )
#
#         # 先操作书籍表
#         # 但是数据里面有列表形式数据所有先删除数据拿返回值打散数据变成关键字参数进行传递
#         authors = validated_data.pop('authors')
#         # 数据在validated_data 里面是关键字的形式所有用**kwargs接收
#         book = Book.objects.create(**validated_data)
#         # 这样原先的author的数据是[1,2],后面数据是(1,2)使用*args接收
#         # 书籍和作者表是多对多的关系,所以要块表操作,正向查询表名小写,添加数据
#         book.authors.add(*authors)
#         # 保存操作数据
#         book.save()
#         return book
#
#     def update(self, instance, validated_data):
#         # 数据里面有列表形式数据所有先删除数据拿返回值打散数据变成关键字参数进行传递
#         authors = validated_data.pop('authors')
#         # print(authors, type(authors))
#         # authors = list(authors)
#         # print(authors, type(authors))
#         for intem in validated_data:  # 把字典进行循环
#             # setattr反射方法: setatter(对象,属性,属性值)
#             # 这个的意思是如果对象对应的属性和属性值就修改属性值,没有就新增属性和属性值
#             setattr(instance, intem, validated_data[intem])
#         # instance是视图函数查询出来的书籍表的对象,书籍表操作作者表相关联的表数据
#         # 把第三张表数据操作
#         instance.authors.set(authors)
#         instance.save()
#         return instance


# # 5 ModelSerialzier的使用
# '''
# # 现在学的ModelSerializer,表示跟表模型一一对应,用法跟之前基本类似
# 1 写序列化类,继承ModelSerializer
# 2 在序列化类中,再写一个类,必须叫
#     class Meta:
#         model=表模型
#          fields=[] # 要序列化的字段
# 3 可以重写字段,一定不要放在class Meta
#     -定制字段,跟之前讲的一样
# 4 自定制的字段,一定要在fields中注册一下
# 5 class Meta: 有个extra_kwargs,为某个字段定制字段参数
# 6 局部钩子,全局钩子,完全一致
# 7 大部分请情况下,不需要重写 create和update了
# '''
#
# class Bookserializers(serializers.ModelSerializer):
#     class Meta:
#         model =Book   # 指定表模型 (相当于把book表中的所有东西复制一份到这里来了)
#         # fields='__all__'  # 把表模型中所有字段都映射过来
#         fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']  # 自定制的字段,一定要在这里注册一下
#         extra_kwargs = {
#             'name': {'max_length': 10, 'required': True},
#             'publish': {'write_only': True},
#             'authors': {'write_only': True}
#         }
#
#     # 自定制字段:publish_detail  author_list 写法有两种,跟之前一模一样
#     publish_detail = serializers.DictField(read_only=True)
#     author_list = serializers.ListField(read_only=True)


# 作业1
# from app01 import models
#
#
# class Bookserializers(serializers.ModelSerializer):
#     class Meta:
#         model = models.Publish
#         fields =['id', 'name', 'addr']


# 作业2
from app01 import models


class Bookserializers(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # fields = '__all__'
        fields = ['id', 'name', 'phone', 'email', 'age']

    # 不是表的字段,一定要重写
    email = serializers.CharField(source='author_detail.email')
    age = serializers.IntegerField(source='author_detail.age')

    def create(self, validated_data):
        print(validated_data)
        # {'name': '刘亦菲', 'phone': '123456', 'author_detail': {'email': '1@qq.com', 'age': 18}}
        author_detail = validated_data.pop('author_detail')
        print(author_detail)
        # {'name': '刘亦菲', 'phone': '123456', 'author_detail': {'email': '1@qq.com', 'age': 18}}

        author_detail_obj = models.AuthorDetail.objects.create(**author_detail)
        print(author_detail_obj)  # AuthorDetail object (6)

        validated_data['author_detail'] = author_detail_obj
        suthor_obj = models.Author.objects.create(**validated_data)
        return suthor_obj

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name')
        instance.phone = validated_data.get('phone')
        instance.author_detail.email = validated_data.get('author_detail').get('email')
        instance.author_detail.age = validated_data.get('author_detail').get('age')
        instance.save()
        instance.author_detail.save()
        return instance

  • 视图层
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.serializer import Bookserializers


# Create your views here.


class bookview(APIView):
    def get(self, request):
        print(1)
        res = models.Book.objects.all()
        print(res)
        # 把查询的表的对象res传入到序列化类中进行数据处理,在Bookserializers()的括号中用instance接收对象
        ser = Bookserializers(instance=res, many=True)
        print(res)
        print(ser.data)
        return Response({'code': 200, 'msg': '成功', 'results': ser.data})

    def post(self, request):
        # 创建数据
        # 接收前端传来的数据去反序列化
        print(request.data)
        res = Bookserializers(data=request.data)  # 反序列化
        # 校验反序列化后的数据
        if res.is_valid():
            print(res.validated_data)  # 打印校验之后的数据
            # 保存数据
            res.save()
            return Response({'code': 200, 'msg': '更新成功'})
        else:
            print(res.errors)  # 打印校验失败的信息
            return Response({'code': 404, 'msg': '创建失败', '失败data': res.errors})


class BookDetailView(APIView):
    # 查询单个数据
    def get(self, request, pk):
        res_obj = models.Book.objects.all().get(pk=pk)
        ser = Bookserializers(res_obj)  # 序列化
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    # 修改数据
    def put(self, request, pk):
        res_obj = models.Book.objects.filter(pk=pk).first()
        print(res_obj)
        ser = Bookserializers(instance=res_obj, data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'results': ser.validated_data})
        else:
            print(ser.validated_data)
            return Response({'code': 100, 'msg': '修改失败', 'results': ser.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).first().delete()
        return Response({'code': 100, 'msg': '删除成功'})







##############################################  第二题作业   #2  Publish的5个接口,ModelSerializer写



# class Publishview(APIView):
#     def get(self, request):
#         res_obj = models.Publish.objects.all()
#         ser = Bookserializers(instance=res_obj, many=True)
#         return Response({'code': 200, 'msg': '成功', 'results': ser.data})
#
#     def post(self, request):
#         ser = Bookserializers(data=request.data)
#         if ser.is_valid():
#             ser.save()
#             return Response({'code': 200, 'msg': '更新成功'})
#         else:
#             return Response({'code': 404, 'msg': '创建失败', '失败data': ser.errors})


# class Publishviewkk(APIView):
#     def get(self, request, pk):
#         res = models.Book.objects.all().get(pk=pk)
#         ser = Bookserializers(instance=res, many=False)
#         return Response({'code': 200, 'msg': '成功', 'results': ser.data})
#
#     # 修改数据
#     def put(self, request, pk):
#         res_obj = models.Publish.objects.filter(pk=pk).first()
#         print(res_obj)
#         ser = Bookserializers(instance=res_obj, data=request.data)
#         if ser.is_valid():
#             print(ser.validated_data)
#             ser.save()
#             return Response({'code': 100, 'msg': '修改成功', 'results': ser.validated_data})
#         else:
#             print(ser.validated_data)
#             return Response({'code': 100, 'msg': '修改失败', 'results': ser.errors})
#
#     def delete(self, request, pk):
#         models.Publish.objects.filter(pk=pk).first().delete()
#         return Response({'code': 100, 'msg': '删除成功'})






# ##############################   第三题作业  
## 3 author的5个接口(写不出来没关系)(
#-新增或修改author时,把author_detail的内容也新增进去


# class Authorview(APIView):
#     # 查询所有数据
#     def get(self, request):
#         res = models.Author.objects.all()
#         ser = Bookserializers(instance=res, many=True)
#         return Response({'code': 200, 'msg': '成功', 'results': ser.data})
#
#     # 增加
#     def post(self, request):
#         res = Bookserializers(data=request.data)
#         if res.is_valid():
#             res.save()
#             return Response({'code': 200, 'msg': '更新成功'})
#         else:
#             return Response({'code': 404, 'msg': '创建失败', '失败data': res.errors})
#
#
#
# class Authorviews(APIView):
#     # 查询一条数据
#     def get(self, request, pk):
#         res = models.Author.objects.filter(pk=pk).first()
#         # res = models.Author.objects.all().get(pk=pk)
#         print(res)
#         ser = Bookserializers(instance=res)
#         return Response({'code': 200, 'msg': '成功', 'results': ser.data})
#
#     # 修改
#     def put(self, request, pk):
#         res = models.Author.objects.filter(pk=pk).first()
#         ser = Bookserializers(data=request.data, instance=res)
#         if ser.is_valid():
#             ser.save()
#             return Response({'code': 100, 'msg': '修改成功', 'results': ser.validated_data})
#         else:
#             return Response({'code': 100, 'msg': '修改失败', 'results': ser.errors})
#
#
#     def delete(self, request, pk):
#         models.Author.objects.filter(pk=pk).first()
#         # models.AuthorDetail.objects.filter(pk=.author_detail.id).delete()
#         return Response({'code': 100, 'msg': '删除成功'})


总结

以上就是今天要讲的内容,本文仅仅简单介绍了的 序列化和反序列化的高级使用 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值