定义Serializer数据库
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。 api
例如,咱们已有了一个数据库模型类BookInfo服务器
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期', null=True)
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
image = models.ImageField(upload_to='booktest', verbose_name='图片', null=True)
咱们想为这个模型类提供一个序列化器,能够定义以下:post
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20)
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
注意:serializer不是只能为数据库模型类定义,也能够为非数据库模型类的数据定义。serializer是独立于数据库以外的存在。测试
经常使用字段类型:ui
read_only:True表示不容许用户本身上传,只能用于api的输出。若是某个字段设置了read_only=True,那么就不须要进行数据验证,只会在返回时,将这个字段序列化后返回url
write_only:与read_only对应;就是用户post过来的数据,后台服务器处理后不会再通过序列化后返回给客户端;最多见的就是咱们在使用手机注册的验证码和填写的密码。spa
Serializer的构造方法为:3d
Serializer(instance=None, data=empty, **kwarg)
说明: rest
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可经过context参数额外添加数据,如
serializer = AccountSerializer(account, context={'request': request})
经过context参数附加的数据,能够经过Serializer对象的context属性获取。
Serializer使用
views
def test(request): return HttpResponse('ok')
urls
urlpatterns = [ url(r'^test/$', views.test) ]
def test(request): book = BookInfo.objects.get(id=5) # 先查询出一个图书对象 serializer = BookInfoSerializer(book) # 构建序列化 print(serializer.data) # 获取序列化数据 {'image': None, 'btitle': '西游记', 'id': 5, 'bread': 10, 'bcomment': 10, 'bpub_date': '1988-01-01'} return HttpResponse('ok')
若是要被序列化的是包含多条数据的查询集QuerySet,能够经过添加many=True参数补充说明
def test(request): book = BookInfo.objects.all() # 先查询出一个图书对象 serializer = BookInfoSerializer(book, many=True) # 构建序列化 print(serializer.data) # 获取序列化数据 {'image': None, 'btitle': '西游记', 'id': 5, 'bread': 10, 'bcomment': 10, 'bpub_date': '1988-01-01'} return HttpResponse('ok')
若是须要序列化的数据中包含有其余关联对象,则对关联对象数据的序列化须要指明。
例如,在定义英雄数据的序列化器时,外键hbook(即所属的图书)字段如何序列化?
咱们先定义HeroInfoSerialzier除外键字段外的其余部分
对于关联字段,能够采用如下几种方式:
此字段将被序列化为关联对象的主键。
hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True) 或 hbook = serializers.PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())
指明字段时须要包含read_only=True或者queryset参数:
使用效果:
def test(request): hero = HeroInfo.objects.get(id=10) # 查询一个英雄对象 serializer = HeroInfoSerializer(hero) # 构建序列化 print(serializer.data) # 返回序列化内容 {'id': 10, 'hcomment': '独孤九剑', 'hname': '令狐冲', 'hbook': 3, 'hgender': 1} return HttpResponse('ok')
报错:说明id不存在
此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
hbook = serializers.StringRelatedField(label='图书')
def test(request): hero = HeroInfo.objects.get(id=11) # 查询一个英雄对象 serializer = HeroInfoSerializer(hero) # 构建序列化 print(serializer.data) # 返回序列化内容 {'hgender': 0, 'hbook': '笑傲江湖', 'id': 11, 'hname': '任盈盈', 'hcomment': '弹琴'} return HttpResponse('ok')
hbook = BookInfoSerializer()
def test(request): hero = HeroInfo.objects.get(id=11) # 查询一个英雄对象 serializer = HeroInfoSerializer(hero) # 构建序列化 print(serializer.data) # 返回序列化内容 {'hgender': 0, 'hbook': OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image', None)]), 'hcomment': '弹琴', 'id': 11, 'hname': '任盈盈'} return HttpResponse('ok')
此字段将被序列化为获取关联对象数据的接口连接
hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')
必须指明view_name参数,以便DRF根据视图名称寻找路由,进而拼接成完整URL。
{'id': 6, 'hname': '乔峰', 'hgender': 1, 'hcomment': '降龙十八掌', 'hbook': 'http://127.0.0.1:8000/books/2/'}
此字段将被序列化为关联对象的指定字段数据
slug_field指明使用关联对象的哪一个字段
hbook = serializers.SlugRelatedField(label='图书', read_only=True, slug_field='bpub_date')
def test(request): hero = HeroInfo.objects.get(id=11) # 查询一个英雄对象 serializer = HeroInfoSerializer(hero) # 构建序列化 print(serializer.data) # 返回序列化内容 {'id': 11, 'hgender': 0, 'hcomment': '弹琴', 'hname': '任盈盈', 'hbook': datetime.date(1995, 12, 24)} return HttpResponse('ok')
序列化器的每一个字段实际都是由该字段类型的to_representation方法决定格式的,能够经过重写该方法来决定格式。
注意,to_representations方法不只局限在控制关联对象格式上,适用于各个序列化器字段类型。
自定义一个新的关联字段:
class BookRelateField(serializers.RelatedField): """自定义用于处理图书的字段""" def to_representation(self, value): return 'Book: %d %s' % (value.id, value.btitle)
hbook = BookRelateField(read_only=True)
def test(request): hero = HeroInfo.objects.get(id=11) # 查询一个英雄对象 serializer = HeroInfoSerializer(hero) # 构建序列化 print(serializer.data) # 返回序列化内容 {'hbook': 'Book: 3 笑傲江湖', 'id': 11, 'hcomment': '弹琴', 'hname': '任盈盈', 'hgender': 0} return HttpResponse('ok')
若是关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每一个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可以使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数便可。
此处仅拿PrimaryKeyRelatedField类型来举例,其余相同。
在BookInfoSerializer中添加关联字段:
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20)
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
使用效果:
def test(request): book = BookInfo.objects.get(id=3) # 查询一个英雄对象 serializer = BookInfoSerializer(book) # 构建序列化 print(serializer.data) # 返回序列化内容 {'image': None, 'id': 3, 'bpub_date': '1995-12-24', 'bcomment': 80, 'bread': 20, 'heroinfo_set': [10, 11, 12, 13], 'btitle': '笑傲江湖'} return HttpResponse('ok')