序列化高级用法之source(了解)
数据准备
# 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) publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') 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)
模型表创建好之后进行数据库迁移,录入数据。
序列化定制字段名字
# serializer.py
from rest_framework import serializers class BookSerializer(serializers.Serializer): # 将字段名name修改为real_name,通过source指定原来的字段名 real_name = serializers.CharField(max_length=32,source='name') price = serializers.CharField() # 一对多外键字段,通过source可以指定外键字段关联的数据(通过外键用的的方式取值) publish = serializers.CharField(source='publish.name') # 多对多,source不能用 authors = serializers.CharField(source='authors.name')
执行结果如下:
序列化高级用法之定制字段的两种方式
要想把数据以下面这种方式返回给前端:
''' { "name": "西游记", "price": "55", "publish":{"name":"北京出版社","addr":"北京"}, # 真实显示出版社表中的所有数据 authors:[{"name":"xxx","phone":"1111"},{"name":"yyy","phone":"12345……"}] # 真实显示本书的所有作者表中的信息 } '''
SerializerMethodField定制
# 定制关联字段的显示形式 -一对多的,显示字典 -多对多,显示列表套字典
# serializer.py
from rest_framework import serializers class BookSerializer(serializers.Serializer): # 将字段名name修改为real_name,通过source指定原来的字段名 name = serializers.CharField(max_length=32) price = serializers.CharField() publish = serializers.SerializerMethodField() # get_后面的字段必须与序列化的字段名一致,即一定得是publish def get_publish(self, obj): # obj指的是当前序列化的对象,即book对象 return {'name': obj.publish.name, 'addr': obj.publish.addr} # 可以自己指定要返回的数据 # 多对多 author_list = serializers.SerializerMethodField() def get_author_list(self, obj): # obj指的是当前序列化的对象,即book对象 l = []for author in obj.authors.all(): l.append({'name': author.name, 'phone': author.phone}) return l
执行结果如下:
在表模型中定制
# models.py
from django.db import models class Book(models.Model): name = models.CharField(max_length=32) price = models.CharField(max_length=32) publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') @property def publish_detail(self): # self指的是当前book对象 return {'name': self.publish.name, 'addr': self.publish.addr} # 可以自己指定要返回的数据 @property def author_list(self): # self指的是当前book对象 l = [] for author in self.authors.all(): l.append({'name': author.name, 'phone': author.phone}) return l
# serializer.py
from rest_framework import serializers class BookSerializer(serializers.Serializer): name = serializers.CharField(max_length=32) price = serializers.CharField() publish_detail = serializers.DictField() author_list = serializers.ListField()
图解:
read_only 和 write_only
- read_only:默认False,设置read_only=True:表明该字段仅用于序列化输出(只能查看,不能修改)
- write_only:默认False,设置write_only=True:表明该字段仅用于反序列化输入(只能修改,不能查看)
# name和price,即用来序列化,又用来反序列化,既写又读 name = serializers.CharField(max_length=32) price = serializers.CharField() # 只用来做序列化,只读, read_only publish_detail = serializers.DictField(read_only=True) author_list = serializers.ListField(read_only=True) # 只用来做反序列化,只写,write_only publish = serializers.CharField(write_only=True) authors = serializers.ListField(write_only=True)
多表关联反序列化保存
新增图书接口
首先要明确一点,前端传入的数据,绑定了外键字段的,是根据绑定的id值进行选择相应的数据传入,而不是直接输入一条数据。类似于下面的格式:
{"name": "西游记", "price": "55", "publish": 1, "authors": [1,2]}
# views.py
from rest_framework.views import APIView from .serializer import BookSerializer from rest_framework.response import Response class BookView(APIView): def post(self,request): ser = BookSerializer(data=request.data) if ser.is_valid(): ser.save() return Response({'code':100,'msg':'新增成功'}) else: return Response({'code':101,'msg':ser.errors})
# serializer.py
from rest_framework import serializers from .models import Book class BookSerializer(serializers.Serializer): # name和price,即用来序列化,又用来反序列化,既写又读 name = serializers.CharField(max_length=32) price = serializers.CharField() # 只用来做反序列化,只写,write_only publish = serializers.CharField(write_only=True) authors = serializers.ListField(write_only=True) # 新增要重写create方法 def create(self, validated_data): # validated_data 校验过后的数据,{"name": "西游记", "price": "55", "publish": 1, "authors": [1,2]} # 新增一本图书 book = Book.objects.create(name=validated_data.get('name'),price=validated_data.get('price'), publish_id=validated_data.get('publish')) # 作者表也要关联上 book.authors.add(*validated_data.get('authors')) # 将列表打散,相当于book.authors.add(1,2) return book
修改图书接口
# urls.py
path('books/<int:pk>/',views.BookDetailView.as_view())
# views.py
class BookDetailView(APIView): def put(self,request,pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(data=request.data,instance=book) if ser.is_valid(): ser.save() return Response({'code':100,'msg':'修改成功'}) else: return Response({'code':101,'msg':ser.errors})
# serializer.py
from rest_framework import serializers from .models import Book class BookSerializer(serializers.Serializer): # name和price,即用来序列化,又用来反序列化,既写又读 name = serializers.CharField(max_length=32) price = serializers.CharField() # 只用来做反序列化,只写,write_only publish = serializers.CharField(write_only=True) authors = serializers.ListField(write_only=True) # 修改要重写update def update(self, instance, validated_data): # validated_data 校验过后的数据,{"name": "西游记", "price": "55", "publish": 1, "authors": [1,2]} instance.name = validated_data.get('name') instance.price = validated_data.get('price') instance.publish_id = validated_data.get('publish') # 注意数据库中外键字段名会自动加_id authors = validated_data.get('authors') # 方法1:先清空,再add # instance.authors.clear() # instance.authors.add(*authors)
# 方法2:也可以直接用set instance.authors.set(authors) instance.save() return instance
反序列化字段校验
总共有4层校验
1. 序列化子内字段自带的校验
name = serializers.CharField(max_length=8, error_messages={'max_length': '最长只有为8位'})
2. 局部钩子
3. 全局钩子
4. validators=[方法,] (先忽略)
ModelSerializer使用
- 上面我们使用的Serializer 序列化类,它不是只能为数据库模型类定义, 也可以为非数据库模型类的数据定义 (也就是自己定义的数据进行序列化 : {“name”:“xxx”,“age”:18}),
- serializer是独立于数据库之外的存在, 需要自己在序列化类中去指定模型类的字段
- 而如果我们想要使用序列化器对应的是Django的模型类, DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类
ModelSerializer相比较于Serializer提供了一些功能
- 基于模型类自动生成一系列字段 (也就是不再需要自己手动定义字段)
- 基于模型类自动为 Serializer 生成 validators,比如 : unique_together
- 包含默认的
create( )
和update( )
的实现, 不再需要重写这两种方法
模型类序列化器的定义
model
:指明参照哪个模型类fields
:指明为模型类的哪些字段生成
代码示例:
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book # 序列化类与表模型Book类建立了关联 # fields='__all__' # 序列化所有Book中的字段 fields = ['name', 'price', 'publish', 'authors', 'publish_detail', 'author_list'] # 新增的字段要在这个表中进行注册 # 定制name反序列化时,最长不能超过8 给字段类加属性---方式一 extra_kwargs = {'name': {'max_length': 8}, 'publish_detail': {'read_only': True}, 'author_list': {'read_only': True}, # publish_detail和author_list是新增的两个字段,只用来序列化,设置read_only 'publish': {'write_only': True}, 'authors': {'write_only': True}, # publish和author只用来反序列化,设置write_only } # 如果Meta写了__all__ ,就相当于,复制了表模型中的所有字段,放在了这里,做了个映射,由此可有得到方式二 # name = serializers.CharField(max_length=32) # price = serializers.CharField(max_length=32) # 定制name反序列化时,最长不能超过8 给字段类加属性---方式二,重写name字段 name = serializers.CharField(max_length=8) # 添加两个新的字段(也可以在表模型中定制) publish_detail = serializers.SerializerMethodField(read_only=True) # get_后面的字段必须与上面的一致,即一定得是publish def get_publish_detail(self, obj): # obj指的是当前序列化的对象,即book对象 return {'name': obj.publish.name, 'addr': obj.publish.addr} author_list = serializers.SerializerMethodField(read_only=True) def get_author_list(self, obj): # obj指的是当前序列化的对象,即book对象 l = [] print(obj) for author in obj.authors.all(): l.append({'name': author.name, 'phone': author.phone}) print(l) return l # 局部钩子和全局钩子跟之前完全一样 def validate_name(self, name): if name.startswith('sb'): raise ValidationError('不能以sb开头') else: return name
标签:serializers,name,之反,only,publish,CharField,多表,序列化 From: https://www.cnblogs.com/chen-ao666/p/17086455.html