drf安装、序列化组件
一、drf的安装使用
1、drf介绍
drf全称djangorestframework,是django的一个第三方app,目的是方便我们快速实现符合restful规范的接口
2、安装使用
2.1 安装模块
1 | djangorestframework |
2.2 django 是2版本,用不了drf最新(适当降版本),会自动卸载django,装最django新版4.x
使用 djagno 3.1.12 可以使用最新版本drf
2.3 注册app(arf是第三方app)
1 2 3 | INSTALLED_APPS = [ 'rest_framework' , ] |
2.4 写路由
1 2 3 4 5 | from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register( 'books' , BookView, 'books' ) urlpatterns + = router.urls |
2.5 写视图类
1 2 3 4 5 | from rest_framework.viewsets import ModelViewSet from .serializer import BookSerializer class BookView(ModelViewSet): queryset = Book.objects. all () serializer_class = BookSerializer |
2.6 写序列化类
1 2 3 4 | class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = "__all__" |
二、序列化组件(重要!!)
1、序列化组件介绍
DRF的序列化组件是该框架的核心部分,用于在Django应用程序中处理复杂数据结构的序列化和反序列化。
它的主要作用是在 models 和 views 视图函数之间建立桥梁,使数据能够在数据库模型和API接口之间进行转换,同时还能够进行数据验证、字段选择和数据转换。
序列化组件有以下作用:
-
序列化(Serialization): 序列化是将数据从复杂的数据结构(如Django模型)转换为可以在API响应中传输的格式(如JSON)。通过使用序列化器,你可以定义模型的字段,并指定哪些字段需要包含在API响应中。这样,当你从数据库中检索数据并将其传递到API响应中时,序列化器会自动将数据转换为适当的格式。
-
反序列化(Deserialization): 反序列化是将API请求中的数据转换为数据库模型或其他Python对象。例如,当用户通过API提交数据以创建或更新资源时,DRF的序列化器可以将传入的数据验证并将其转换为数据库模型实例,然后保存到数据库中。
-
数据验证和转换: 序列化组件允许你定义字段的验证规则,例如字段是否必需、数据类型是否正确以及其他自定义验证。它还允许你在保存数据之前对数据进行自定义转换,以便确保数据的一致性和准确性。
-
嵌套关系处理: 在复杂的数据模型中,可能存在多层嵌套的关系。序列化器允许你在API响应中嵌套关联的数据,并在API请求中处理这些嵌套的关系。
-
字段选择和映射: 有时候你可能只需要返回模型的部分字段,而不是全部字段。序列化器允许你选择要包含在API响应中的字段,从而减少传输的数据量。此外,它还支持字段的重命名,使API的字段名与模型的字段名可以不同。
总之,DRF的序列化组件使得在Django项目中处理复杂数据结构、数据验证和数据转换变得更加简单和灵活。通过定义序列化器,你可以更好地控制数据的输入和输出,同时提供一种清晰的方式来处理API请求和响应中的数据。
2、序列化组件的引入
2.1 新建一个py文件---> serializer.py ---> 写一个序列化类
继承drf提供的serializers.Serializer
在类中写要序列化的字段:字段类---> 跟之前学过的models.py中的字段类完全对应,但是比models多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # 写序列化类 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 拿到序列化后的数据
1 | serializer.data 可能是列表,可能是字典 |
2.4 使用drf提供的Resposne 返回
1 | from rest_framework.response import Response |
三、
1、 路由
1 2 3 4 5 6 7 8 | 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、 视图类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 反序列化保存
-新增数据:(写,反序列化)
1 2 3 | ser = BookSerializer(data = request.data) ser.save() - - - >触发 序列化类中的 create - - - 》为什么?内部做了判断:根据是否有instance create中,自己写保存到哪个表中:有数据 - - 》保存到某个表中 |
-修改数据:(写,反序列化)
1 2 3 | ser = BookSerializer(instance = 待修改对象,data = request.data) ser.save() - - - >触发 序列化类中的 update - - - 》为什么?内部做了判断:根据是否有instance update中,有待修改对象,有数据 - - - 》修改完保存即可 - - 》两种方式 |
3 序列化类中重写 update、create 方法的 return instance 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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,会根据这个返回值做序列化
1 2 3 4 | 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、 常用字段类
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 写序列化类的时候,写了CharField,IntegerField 跟django中models中的类似 BooleanField、CharField、 IntegerField、DecimalField、 DateField、FileField # 序列化类中的和models中的一一对应,但是序列化类中多一些 # 多的--->暂时有个印象,后面会详细讲 ListField DictField # 使用场景 {name:金鹏没,price: 99 ,publish:{name:xx出版社,addr:南京},authors:[{},{}]} |
2、
1 2 3 4 5 6 | # 字段类上,可以传参数,是做反序列化校验用的(前端拿到的数据做反序列化) CharField:max_length,min_lenght,allow_blank: 可以不传 IntegerField:max_value,min_value # 所有字段都可以用通用的 - 非常重要:read_only,write_only - default,required,allow_null |
3、字段类的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 如下写法,就能修改序列化的字段 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # 方案一:使用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、效果
序列化类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # 路由 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、定义一个作者序列化类,注意更新和创建方法的重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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类,序列化操作即实例化一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 ) |
1、ModelSerializer
是一个用于简化Django模型序列化和反序列化的强大工具。它是基于Django模型的序列化器,可以自动生成序列化和反序列化逻辑,减少了编写重复代码的工作
2、实例(图书、出版社、作者)
2.1 serializer 序列化类文件
定义一个 BookSerializer 类,继承 serializers.ModelSerializer类。再将BookSerializer类导入到views中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ###### 图书 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视图文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # 导入序列化类,通过类去实例化对象 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 路由
1 2 3 4 5 6 | 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 序列化类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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) 内置函数。
用于批量设置对象的属性值。属于使用内置函数来实现反射操作
1 2 3 4 5 | setattr ( object , name, value): 参数 object 是要操作的对象。 参数 name 是属性名。 参数 value 是要设置的属性值。 |
3.2 views
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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 内部
九、魔术方法之点(.)拦截
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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) |