drf安装、序列化组件

一、drf的安装使用

1、drf介绍

  drf全称djangorestframework,是django的一个第三方app,目的是方便我们快速实现符合restful规范的接口

2、安装使用

2.1  安装模块

djangorestframework

2.2 django 是2版本,用不了drf最新(适当降版本),会自动卸载django,装最django新版4.x

使用 djagno 3.1.12 可以使用最新版本drf

2.3 注册app(arf是第三方app)

INSTALLED_APPS = [
            'rest_framework',  
        ]

2.4  写路由

from rest_framework.routers import DefaultRouter
    router = DefaultRouter()
    router.register('books', BookView, 'books')
    
    urlpatterns += router.urls

2.5 写视图类

from rest_framework.viewsets import ModelViewSet
from .serializer import BookSerializer
    class BookView(ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer

2.6  写序列化类

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"

二、序列化组件(重要!!)

1、序列化组件介绍

DRF的序列化组件是该框架的核心部分,用于在Django应用程序中处理复杂数据结构的序列化和反序列化

它的主要作用是在 models 和 views 视图函数之间建立桥梁,使数据能够在数据库模型和API接口之间进行转换,同时还能够进行数据验证、字段选择和数据转换。

序列化组件有以下作用:

  1. 序列化(Serialization): 序列化是将数据从复杂的数据结构(如Django模型)转换为可以在API响应中传输的格式(如JSON)。通过使用序列化器,你可以定义模型的字段,并指定哪些字段需要包含在API响应中。这样,当你从数据库中检索数据并将其传递到API响应中时,序列化器会自动将数据转换为适当的格式。

  2. 反序列化(Deserialization): 反序列化是将API请求中的数据转换为数据库模型或其他Python对象。例如,当用户通过API提交数据以创建或更新资源时,DRF的序列化器可以将传入的数据验证并将其转换为数据库模型实例,然后保存到数据库中。

  3. 数据验证和转换: 序列化组件允许你定义字段的验证规则,例如字段是否必需、数据类型是否正确以及其他自定义验证。它还允许你在保存数据之前对数据进行自定义转换,以便确保数据的一致性和准确性。

  4. 嵌套关系处理: 在复杂的数据模型中,可能存在多层嵌套的关系。序列化器允许你在API响应中嵌套关联的数据,并在API请求中处理这些嵌套的关系。

  5. 字段选择和映射: 有时候你可能只需要返回模型的部分字段,而不是全部字段。序列化器允许你选择要包含在API响应中的字段,从而减少传输的数据量。此外,它还支持字段的重命名,使API的字段名与模型的字段名可以不同。

总之,DRF的序列化组件使得在Django项目中处理复杂数据结构、数据验证和数据转换变得更加简单和灵活。通过定义序列化器,你可以更好地控制数据的输入和输出,同时提供一种清晰的方式来处理API请求和响应中的数据。

2、序列化组件的引入

2.1  新建一个py文件---> serializer.py ---> 写一个序列化类

继承drf提供的serializers.Serializer

在类中写要序列化的字段:字段类---> 跟之前学过的models.py中的字段类完全对应,但是比models多

# 写序列化类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import User, Book

class UserSerializer(serializers.Serializer):
    # 写要序列化的字段
    # 字段限制
    name = serializers.CharField(max_length=8, min_length=3, required=True)
    hobby = serializers.CharField()
    password = serializers.CharField()
    age = serializers.IntegerField()

    # 局部钩子
    # 写一个方法  validate_字段名,传入要校验的数据--》前端传入的
    def validate_name(self, value):
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')  # 如果校验失败,抛ValidationError
        return value  # 如果校验通过,返回 value,后续继续用

    # 全局钩子
    # 名字和hobby不能一致   多个字段的同时校验
    def validate(self, attrs):  # 前端传入的所有数据,局部校验通过之后attrs 字典
        name = attrs.get('name')
        hobby = attrs.get('hobby')
        if name == hobby:
            raise ValidationError('名字和爱好不能一样')
        else:
            return attrs

    # 重写create方法
    def create(self, validated_data):  # validated_data:前端传入,校验过后的数据
        user = User.objects.create(**validated_data)
        return user

2.2 在视图类中,使用序列化类

多条:serializer=UserSerializer(instance=users,many=True)

# instance 要序列化的对象实例 (qs,单个对象)   many=True表示序列化多条,如果不写就是序列化一条

单条:serializer=UserSerializer(instance=user)

2.3 拿到序列化后的数据

serializer.data  可能是列表,可能是字典

2.4 使用drf提供的Resposne 返回

from rest_framework.response import Response

三、序列化组件快速使用之序列化

1、 路由

from django.contrib import admin
from django.urls import path
from app01.views import BookView,BookDetailView

urlpatterns = [
    path('books/', BookView.as_view()),
    path('books/<int:pk>', BookDetailView.as_view()),
]

2、 视图类

class BookView(APIView):
    # 查看所有的数据
    def get(self, request):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response({'code': 100, '书名查询成功': ser.data})  # ser.data[1].get('name') 取一条记录的书名

    # 添加一本书
    def post(self, request, *args, **kwargs):
        ser = BookSerializer(data=request.data)  # 获取前端传来的数据(这里是APIView,可以在request.data中获取 )
        if ser.is_valid():
            ser.save()  # 调用了序列化类的save:内部会触发序列化类中,数据库中实例没有数据执行create方法,否则执行update方法 ,不是models中的book.save(),这里是序列化提供的save
            return Response({'code': 200, 'msg': '添加成功'})
        else:
            return Response({'code': 400, 'msg': ser.errors})

class BookDetailView(APIView):
    # 修改数据一本书
    def put(self, request, pk):
        # 要用查出来的对象,使用传入的数据,做修改
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, 'msg': '修改成功'})
        else:
            return Response({'code': 400, 'msg': ser.errors})

    # 删除一本书
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 200, 'msg': '删除成功'})

    # 获取一本书
    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, many=False)
        return Response({'code': 200, 'msg': '查询单条成功', '书名': ser.data.get('name')})

3、 序列化类 serializer.py

class BookSerializer(serializers.Serializer):
    # 写要序列化的字段
    # 字段自己
    name = serializers.CharField(max_length=8, min_length=3, required=True)
    price = serializers.IntegerField(max_value=200, min_value=50)

    # 局部钩子
    # 写一个方法  validate_字段名,传入要校验的数据--》前端传入的
    def validate_name(self, value):
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')  # 如果校验失败,抛ValidationError
        return value  # 如果校验通过,返回 value,后续继续用

    # 重写create方法(添加时候使用)
    def create(self, validated_data):  # validated_data:前端传入,校验过后的数据
        return Book.objects.create(**validated_data)

    # 重写update方法(添加时候使用)
    def update(self, instance, validated_data):
        # instance是待修改的对象(books或者pk)validated_data是验证过的数据 本质还是request.data经过了数据校验
        # 方式一
        # instance.name = validated_data.get('name')
        # instance.price = validated_data.get('price')
        # instance.save()
        # return instance

        # 方式二 反射是通过字符串动态的获取或设置属性或方法
        # get=getattr(self,'get')
        # get()
        for k in validated_data:  # {"name":"西游记","price":99,"publish":南京出版社}
            setattr(instance, k, validated_data.get(k))  # books, key, value
        instance.save()
        return instance

    def delete(self, instance):
        return Book.objects.filter(pk=instance).delete()

总结:

1 序列化校验:

ser.is_valid() 就会走校验

2 反序列化保存

-新增数据:(写,反序列化)

ser = BookSerializer(data=request.data)
ser.save()--->触发 序列化类中的 create---》为什么?内部做了判断:根据是否有instance
create中,自己写保存到哪个表中:有数据--》保存到某个表中

-修改数据:(写,反序列化)

ser = BookSerializer(instance=待修改对象,data=request.data)
ser.save()--->触发 序列化类中的 update---》为什么?内部做了判断:根据是否有instance
update中,有待修改对象,有数据---》修改完保存即可--》两种方式

3  序列化类中重写 update、create 方法的 return instance 源码

    def update(self, instance, validated_data):
        raise_errors_on_nested_writes('update', self, validated_data)
        info = model_meta.get_field_info(instance)

        m2m_fields = []
        for attr, value in validated_data.items():
            if attr in info.relations and info.relations[attr].to_many:
                m2m_fields.append((attr, value))
            else:
                setattr(instance, attr, value)

        instance.save()

        for attr, value in m2m_fields:
            field = getattr(instance, attr)
            field.set(value)

        return instance

补充:重写update方法后,return instance,返回的instance最后干啥了?

只要在视图类中调用ser.data,会根据这个返回值做序列化

    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, many=False)
        return Response({'code': 200, 'msg': '查询单条成功', '书名': ser.data.get('name')})

四、序列化类 serializer.py 常用字段类和参数

1、 常用字段类

# 写序列化类的时候,写了CharField,IntegerField  跟django中models中的类似
BooleanField、CharField、
IntegerField、DecimalField、
DateField、FileField

# 序列化类中的和models中的一一对应,但是序列化类中多一些

# 多的--->暂时有个印象,后面会详细讲
ListField
DictField

# 使用场景
	{name:金鹏没,price:99,publish:{name:xx出版社,addr:南京},authors:[{},{}]}

2、常用字段参数

# 字段类上,可以传参数,是做反序列化校验用的(前端拿到的数据做反序列化)        CharField:max_length,min_lenght,allow_blank: 可以不传
IntegerField:max_value,min_value
    
 # 所有字段都可以用通用的
-非常重要:read_only,write_only
-default,required,allow_null

3、字段类的属性高级用法source(了解)

# 如下写法,就能修改序列化的字段
class BookSerializer(serializers.Serializer):
    # 用法一:最简单,拿表中的字段
    xxx = serializers.CharField(source='name')
    # 用法二 :跨表查询
    publish = serializers.CharField(source='publish.name') # 自动对应成出版社的名字 可以通过 .  跨表查询
    #用法三:表模型中写方法,拿到方法的返回值
    yyy = serializers.CharField(source='get_name')
    ### models.py中
    @property
    def get_name(self):
        return self.name+'sb'
    
    
# 前端看到:
    {
        "xxx": "西游记",
        "price": 199,
        "publish": "南京出版社"
    },

五、定制返回字段

1、三种方案,这里介绍两种

# 方案一:使用SerializerMethodField 定制
	在序列化类中使用SerializerMethodField
    publish_detail = serializers.SerializerMethodField()
    def get_publish_detail(self, obj): # 返回什么,序列化后publish就是什么
        # obj 就是序列化到的book对象
     # publish = obj.publish
        return {'name': self.publish.name, 'addr': self.publish.addr}
    
# 方案二: 在表模型中定制
    -1 Book表模型中写方法,包装成数据属性
    	@property
        def publish_dict(self):
            return {'name': self.publish.name}
    -2 序列化类中
    	 publish_dict=serializers.DictField()

2、效果

六、多表关联序列化和反序列化

以后一个序列化类,想即做序列化,又做反序列化,会出现问题:字段不匹配,尤其是多表关联的字段

以图书、作者、出版社为例

序列化类

class BookSerializer(serializers.Serializer):
    # 字段自己
    name = serializers.CharField(max_length=8, min_length=3)  # 既做序列化又做反序列化
    price = serializers.IntegerField(max_value=500, min_value=40)  # 不写就是既做序列化又做反序列化
    # publish = serializers.IntegerField()

    # 这俩只做序列化(在models中定义,用来定制化给前端返回,给别人的数据做序列化)
    publish_dict = serializers.DictField(read_only=True)  # 只做序列化
    author_list = serializers.ListField(read_only=True)  # 只做序列化

    # 这俩只做反序列化(接收前端传进来的数据)
    publish_id = serializers.IntegerField(write_only=True)  # 反序列化
    authors = serializers.ListField(write_only=True)  # 反序列化

    # 局部钩子
    # 写一个方法  validate_字段名,传入要校验的数据--》前端传入的
    def validate_name(self, value):
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return value

    # 全局钩子(密码和确认密码是否一致)
    # 多个字段的同时校验,这里book只有name和price两个字段不做校验
    # def validate(self, attrs):  # 前端传入的所有数据,校验过后attrs 字典
    #     name = attrs.get('name')
    #     hobby = attrs.get('hobby')
    #     if name == hobby:
    #         raise ValidationError('名字和爱好不能一样')
    #     else:
    #         return attrs

    # 新增书籍,重写create方法
    def create(self, validated_data):  # {"name":"111sb111","price":999,"publish":1,"authors":[1,2]}
        authors = validated_data.pop('authors')  # 弹出authors,剩下其他数据
        book = Book.objects.create(**validated_data)  # 剩下的数据为书名和价格,验证通过后的字典数据,打散成:k:v
        # 增加中间表的记录:图书和作者的关系 set 先删除再增加,add直接增加
        book.authors.add(*authors)  # 向中间表中存入:这个图书关联的作者
        return book

    # 修改书籍,重写update方法
    def update(self, instance, validated_data):
        # 弹出authors,剩下其他数据
        authors = validated_data.pop('authors')
        # print(authors)  # [1, 3]

        # 更新书名和价格和出版社id
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish_id = validated_data.get('publish_id')
        instance.save()

        # 更新图书和作者的关系
        instance.authors.clear()  # 先清除原有的关系数据
        instance.authors.add(*authors)  # 重新添加

        return instance

views

class BookView(APIView):
    # 查看所有的数据
    def get(self, request):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response({'code': 100, '书名查询成功': ser.data})  # ser.data[1].get('name') 取一条记录的书名

    # 添加一本书
    def post(self, request, *args, **kwargs):
        ser = BookSerializer(data=request.data)  # 获取前端传来的数据(这里是APIView,可以在request.body中获取 )
        if ser.is_valid():
            ser.save()  # 调用了序列化类的save:内部会触发序列化类中,数据库中实例没有数据执行create方法,否则执行update方法 ,不是models中的book.save(),这里是序列化提供的save
            return Response({'code': 200, 'msg': '添加成功'})
        else:
            return Response({'code': 400, 'msg': ser.errors})


class BookDetailView(APIView):
    # 修改数据一本书
    def put(self, request, pk):
        # 要用查出来的对象,使用传入的数据,做修改
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, 'msg': '修改成功'})
        else:
            return Response({'code': 400, 'msg': ser.errors})

    # 删除一本书
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 200, 'msg': '删除成功'})

    # 获取一本书
    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, many=False)
        return Response({'code': 200, 'msg': '查询单条成功', '书名': ser.data.get('name')})

路由和model

# 路由
urlpatterns = [
    # BookView.as_view()  类的方法,类来调用,自动把类传入
    path('books/', BookView.as_view()),
    path('books/<int:pk>', BookDetailView.as_view()),
]

# models
class Book(models.Model):
    name = models.CharField(max_length=64)
    price = models.IntegerField()
    # 外键
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    @property
    def publish_dict(self):  # self == book
        return {'name': self.publish.name, 'addr': self.publish.addr}


    def author_list(self):
        l = []
        for author in self.authors.all():
            l.append({'name': author.name, 'sex': author.sex, 'age': author.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)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

七、一对一表关系接口案例

1、定义一个作者序列化类,注意更新和创建方法的重写

class AuthorSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=9, min_length=2)
    age = serializers.CharField(max_length=120)
    sex = serializers.CharField()

    # 反序列化,存入数据库中
    addr = serializers.CharField(write_only=True)
    phone = serializers.CharField(write_only=True)

    # 序列化定制返回,给前端返回的数据
    author_detail_dict = serializers.DictField(read_only=True)

    # 局部钩子
    def validate_name(self, value):
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return value

    def create(self, validated_data):
        addr = validated_data.pop('addr')
        phone = validated_data.pop('phone')

        # 先添加外键指向的表
        author_detail = AuthorsDetail.objects.create(addr=addr, phone=phone)

        # 再添加author表
        author = Author.objects.create(author_detail=author_detail, **validated_data)

        return author

    def update(self, instance, validated_data):
        # 作者详情
        AuthorsDetail.objects.update(addr=instance.author_detail.addr, phone=instance.author_detail.phone)

        # print(validated_data)  # {'name': '老徐2', 'age': '18', 'sex': '男', 'addr': '不要去烫头', 'phone': '11'}
        for i in validated_data:
            setattr(instance, i, validated_data[i])
            setattr(instance.author_detail, i, validated_data[i])
        instance.save()
        instance.author_detail.save()
        return instance

2、views 视图函数

导入AuthorSerializer类,序列化操作即实例化一个对象

class AuthorView(APIView):
    def get(self, request):
        author = Author.objects.all()
        ser = AuthorSerializer(instance=author, many=True)
        return Response({'code': 200, 'msg': '查询成功', 'data': ser.data})

    def post(self, request):
        ser = AuthorSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, 'msg': '添加成功', "result": ser.data})
        else:
            return Response({'code': 201, 'msg': ser.errors})

class Author_DetailView(APIView):
    def get(self, request, pk):
        author = Author.objects.filter(pk=pk).first()
        ser = AuthorSerializer(instance=author, many=False)
        return Response({'code': 200, 'msg': '单挑查询成功', 'data': ser.data})

    def put(self, request, pk):
        author = Author.objects.filter(pk=pk).first()
        ser = AuthorSerializer(instance=author, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, "msg": "修改成功"})
        else:
            return Response({'code': 201, "msg": "修改失败"})

    def delete(self, request, pk):
        author = Author.objects.filter(pk=pk).first()
        author.author_detail.delete()
        author.delete()
        return Response({'code': 200, 'msg': '删除成功'})

注意:两个提示信息字段

'msg': ser.errors : 字段限制、局部钩子、全局钩子提示信息

"result": ser.data:序列化返回内容

3、models 文件

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)
    # 外键
    author_detail = models.OneToOneField(to="AuthorsDetail", on_delete=models.CASCADE, null=True)
    # 这里null=True,在迁移的时候允许这里为空

    @property
    def author_detail_dict(self):
        return {'addr': self.author_detail.addr, "phone": self.author_detail.phone}


class AuthorsDetail(models.Model):
    phone = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

八、ModelSerializer的使用

1、ModelSerializer

是一个用于简化Django模型序列化和反序列化的强大工具。它是基于Django模型的序列化器,可以自动生成序列化和反序列化逻辑,减少了编写重复代码的工作

2、实例(图书、出版社、作者)

2.1  serializer 序列化类文件

定义一个 BookSerializer 类,继承 serializers.ModelSerializer类。再将BookSerializer类导入到views中

class BookSerializer(serializers.ModelSerializer):
    # 方式2 定制返回字段(自定义字段也需要在fields中注册)
    publish_dict = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 表关系自带的字段会自动映射
    class Meta:  # 类里面又定义一个类
        model = Book
        # fields = '__all__'  # 数据太全,有的字段不想做序列化
        fields = ['name', 'price', 'publish_dict', 'author_list', 'publish', 'authors']  # 外键字段也写进去,之做反序列化
        extra_kwargs = {
            'name': {'max_length': 8, 'min_length': 3},
            'publish': {'write_only': True},
            'authors': {'write_only': True}
        }

    # 局部钩子和全局钩子和之前一样
    def validate_name(self, value):
        if value.startswith('sb'):
            raise ValidationError('不能以sb开头')
        return value

    # 多个字段的同时校验,这里book只有name和price两个字段不做校验
    # def validate(self, attrs):  # 前端传入的所有数据,校验过后attrs 字典
    #     name = attrs.get('name')
    #     hobby = attrs.get('hobby')
    #     if name == hobby:
    #         raise ValidationError('名字和爱好不能一样')
    #     else:
    #         return attrs

注:

extra_kwargs 字典中写字段限制规则,和反序列化字段

这里的局部钩子和全局钩子写法和之前一致。

2.2 models 文件

###### 图书
class Book(models.Model):
    name = models.CharField(max_length=64)
    price = models.IntegerField()
    # 外键
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    @property
    def publish_dict(self):  # self == book
        return {'name': self.publish.name, 'addr': self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author in self.authors.all():
            l.append({'name': author.name, 'sex': author.sex, 'age': author.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)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)
    # 外键
    author_detail = models.OneToOneField(to="AuthorsDetail", on_delete=models.CASCADE, null=True)
    # 这里null=True,在迁移的时候允许这里为空

    @property
    def author_detail_dict(self):
        return {'addr': self.author_detail.addr, "phone": self.author_detail.phone}

2.3 views视图文件

# 导入序列化类,通过类去实例化对象
from .serializer import  BookSerializer

## 不带pk
class BookView(APIView):
    # 查看所有的数据
    def get(self, request):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response({'code': 100, 'data': ser.data})  # ser.data[1].get('name') 取一条记录的书名

    # 添加一本书
    def post(self, request, *args, **kwargs):
        ser = BookSerializer(data=request.data)  # 获取前端传来的数据(这里是APIView,可以在request.body中获取 )
        if ser.is_valid():
            ser.save()  # 调用了序列化类的save:内部会触发序列化类中,数据库中实例没有数据执行create方法,否则执行update方法 ,不是models中的book.save(),这里是序列化提供的save
            return Response({'code': 200, 'msg': '添加成功'})
        else:
            return Response({'code': 400, 'msg': ser.errors})

## 带pk
class BookDetailView(APIView):
    # 修改数据一本书
    def put(self, request, pk):
        # 要用查出来的对象,使用传入的数据,做修改
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, 'msg': '修改成功'})
        else:
            return Response({'code': 400, 'msg': ser.errors})

    # 删除一本书
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 200, 'msg': '删除成功'})

    # 获取一本书
    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, many=False)
        return Response({'code': 200, 'msg': '查询单条成功', '书名': ser.data.get('name')})

2.4 path 路由

from app01.views import BookView, BookDetailView
urlpatterns = [
    # BookView.as_view()  类的方法,类来调用,自动把类传入
    path('books/', BookView.as_view()),
    path('books/<int:pk>', BookDetailView.as_view()),
]

3、ModelSerializer 一对一关系表案例

3.1  serializer 序列化类

class AuthorSerializer(serializers.ModelSerializer):
    # # 高级定制化,序列化返回

    author_detail_dict = serializers.DictField(read_only=True)

    class Meta:  # 类里面又定义一个类
        model = Author
        # fields = '__all__'  # 数据太全,有的字段不想做序列化
        fields = ['name', 'age', 'sex', 'author_detail', 'author_detail_dict', 'addr', 'phone']  # 外键字段也写进去,之做反序列化
        extra_kwargs = {
            'name': {'max_length': 8, 'min_length': 2},
            'author_detail': {'write_only': True},
        }

    # 反序列化,写入数据库
    phone = serializers.CharField(write_only=True)
    addr = serializers.CharField(write_only=True)

    def create(self, validated_data):
        print(validated_data)  # {'name': '酒仙', 'age': 28, 'sex': '男', 'addr': '斗气大陆', 'phone': '193'}

        # 获取前端的数据,从validated_data里面拿
        addr = validated_data.pop('addr')
        phone = validated_data.pop('phone')
        # 先添加作者详情表
        author_detail = AuthorsDetail.objects.create(addr=addr, phone=phone)
        # 再添加作者表
        author = Author.objects.create(author_detail=author_detail, **validated_data)
        return author

    def update(self, instance, validated_data):
        # 更新的逻辑,使用setattr字段会自动对应
        for k in validated_data:
            setattr(instance, k, validated_data[k])
            setattr(instance.author_detail, k, validated_data[k])
            instance.save()
            instance.author_detail.save()
        return instance

补充:

更新环节使用了 setattr(object, name, value) 内置函数。 用于批量设置对象的属性值。属于使用内置函数来实现反射操作

setattr(object, name, value):

参数 object 是要操作的对象。
参数 name 是属性名。
参数 value 是要设置的属性值。

3.2  views

from .serializer import AuthorSerializer


class AuthorView(APIView):
    def get(self, request):
        author = Author.objects.all()
        ser = AuthorSerializer(instance=author, many=True)
        return Response({'code': 200, 'msg': '查询成功', 'res': ser.data})

    def post(self, request):
        ser = AuthorSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, 'msg': '添加成功', "result": ser.data})
        else:
            return Response({'code': 201, 'msg': ser.errors})


class Author_DetailView(APIView):
    def get(self, request, pk):
        author = Author.objects.filter(pk=pk).first()
        ser = AuthorSerializer(instance=author, many=False)
        return Response({'code': 200, 'msg': '单挑查询成功', 'data': ser.data})

    def put(self, request, pk):
        author = Author.objects.filter(pk=pk).first()
        ser = AuthorSerializer(instance=author, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 200, "msg": "修改成功"})
        else:
            return Response({'code': 201, "msg": "修改失败"})

    def delete(self, request, pk):
        author = Author.objects.filter(pk=pk).first()
        author.author_detail.delete()
        author.delete()
        return Response({'code': 200, 'msg': '删除成功'})

4、总结

  • 写了 class Meta:model = Book;fields = '__all__' 自动映射表中字段,包括字段属性
  • fields = 列表----》要序列化和反序列化的字段都放在这里,表中没有,也要注册
  • extra_kwargs 给某个字段增加字段属性(包括read_only和write_only)
  • 局部钩子和全局钩子一模一样
  • 一般情况下不需要重写update和create---》即便多表关联
  • 可以重写字段,单一定不要写在class Meta 内部

九、魔术方法之点(.)拦截

class Person():
    # 获取属性值,属性不存在会触发执行
    def __getattr__(self, item):  # item参数获取对象实例传来的值, __getattr__属性不存在会触发执行
        # print(item)
        # print(type(item))
        return 'jingzhiz'

    def __setattr__(self, key, value):
        print(key)
        print(value)
        object.__setattr__(self, key, value)  # 类调用方法,成普通函数有几个值就传几个值


p = Person()
# print(p.name)  #  jingzhiz 返回值

p.name = '彭于晏'
print(p.name)

  

 

  

 

posted @ 2023-08-31 16:27  凡人半睁眼  阅读(74)  评论(0编辑  收藏  举报