serializers.py
来编写
Serializer
),并继承自Serializer
models.py
),序列化器中的字段名需要与模型一致,字段可以比模型字段多或少OneToOneField
、ManyToManyField
、ForeignKey
),在有外键字段里面关联序列化时用外键名,在没有外键字段里面关联序列化多时用模型名小写_setmany=true
instance
参数,如果传的查询集需要在指定many=true
序列化器对象.data
属性即可获取创建数据模型后,在后台添加点测试数据
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
created_time = models.DateField(auto_now_add=True)
publish = models.ForeignKey('Publish',on_delete=models.CASCADE)
class Meta: # 模型元选项
# db_table = 'tb_column' # 在数据库中的表名,否则Django自动生成为app名字_类名
# ordering = ['index']
verbose_name = '书名'
verbose_name_plural = verbose_name
def __str__(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=20)
book = models.ManyToManyField(Book)
class Meta: # 模型元选项
# db_table = 'tb_column' # 在数据库中的表名,否则Django自动生成为app名字_类名
# ordering = ['index']
verbose_name = '作者'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Publish(models.Model):
publish = models.CharField(max_length=32)
class Meta: # 模型元选项
# db_table = 'tb_column' # 在数据库中的表名,否则Django自动生成为app名字_类名
# ordering = ['index']
verbose_name = '出版社'
verbose_name_plural = verbose_name
def __str__(self):
return self.publish
class AuthorDetail(models.Model):
address = models.CharField(max_length=32)
author = models.OneToOneField(Author,on_delete=models.CASCADE)
class Meta: # 模型元选项
# db_table = 'tb_column' # 在数据库中的表名,否则Django自动生成为app名字_类名
# ordering = ['index']
verbose_name = '详情'
verbose_name_plural = verbose_name
def __str__(self):
return self.address
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
created_time = serializers.DateField()
python manage.py shell
In [3]: from book.serializers import BookSerializer
In [4]: from book.models import Book
In [5]: book = Book.objects.get(pk=1)
In [6]: ser = BookSerializer(book)
In [7]: ser.data
Out[7]: {'title': 'Python', 'created_time': '2021-10-08'}
queryset
对象)
In [1]: from book.serializers import BookSerializer
In [2]: from book.models import Book
In [3]: books = Book.objects.all()
In [4]: sers = BookSerializer(books,many=True)
In [5]: sers.data
Out[5]: [OrderedDict([('title', 'Python'), ('created_time', '2021-10-08')]), OrderedDict([('title', 'Vue'), ('created_time', '2021-10-08')])]
单获取的是多个对象需要指定
many=True
# models.py 为 Book模型添加@property方法
class Book(models.Model):
title = models.CharField(max_length=32)
created_time = models.DateField(auto_now_add=True)
publish = models.ForeignKey('Publish',on_delete=models.CASCADE)
class Meta: # 模型元选项
# db_table = 'tb_column' # 在数据库中的表名,否则Django自动生成为app名字_类名
# ordering = ['index']
verbose_name = '书名'
verbose_name_plural = verbose_name
def __str__(self):
return self.title
# @property是python的一种装饰器,是用来修饰方法的。
# 我们可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性
# ,可以与所定义的属性配合使用,这样可以防止属性被修改。
@property
def ext(self):
return f'出版社:name={self.publish.publish}'
# serializers.py 序列化额外字段
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
created_time = serializers.DateField()
# 通过定义模型只读属性获取,这里应与@propert装饰器作用下的函数名名称一致
ext = serializers.CharField(max_length=20)
In [1]: from book.serializers import BookSerializer
In [2]: from book.models import Book
In [3]: books = Book.objects.all()
In [4]: sers = BookSerializer(books,many=True)
In [5]: sers.data
Out[5]: [OrderedDict([('title', 'Python'), ('created_time', '2021-10-08'), ('ext', '出版社:name=CQJTU')]), OrderedDict([('title', 'Vue'), ('created_tim
e', '2021-10-08'), ('ext', '出版社:name=CQJTU')])]
book = Book.objects.get(pk=2)
In [7]: ser = BookSerializer(book)
In [8]: ser.data
Out[8]: {'title': 'Vue', 'created_time': '2021-10-08', 'ext': '出版社:name=CQJTU'}
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
created_time = models.DateField(auto_now_add=True)
publish = models.ForeignKey('Publish',on_delete=models.CASCADE)
class Meta: # 模型元选项
# db_table = 'tb_column' # 在数据库中的表名,否则Django自动生成为app名字_类名
# ordering = ['index']
verbose_name = '书名'
verbose_name_plural = verbose_name
def __str__(self):
return self.title
# @property是python的一种装饰器,是用来修饰方法的。
# 我们可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性
# ,可以与所定义的属性配合使用,这样可以防止属性被修改。
@property
def ext(self):
return f'出版社:name={self.publish.publish}'
@property
def eee(self):
return f'作者:{[i.name for i in self.author_set.all()]}'
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
created_time = serializers.DateField()
# 通过定义模型只读属性获取
ext = serializers.CharField(max_length=20) # 名称对应相同则不需要指定source
author = serializers.CharField(max_length=10,source="eee") # 不同时则需要指定source
# SerializerMethodField 在此序列化类中get_xxx来重写
ext_info = serializers.SerializerMethodField(label="额外字段")
def get_ext_info(self,obj):
return f'出版社:{obj.publish}'
In [1]: from book.serializers import BookSerializer
In [2]: from book.models import Book
In [3]: books = Book.objects.all()
In [4]: sers = BookSerializer(books,many=True)
In [5]: sers.data
Out[5]: [OrderedDict([('title', 'Python'), ('created_time', '2021-10-08'), ('ext', '出版社:name=CQJTU'), ('author', "作者:['AAA', 'asd']"), ('ext_info
', '出版社:CQJTU')]), OrderedDict([('title', 'Vue'), ('created_time', '2021-10-08'), ('ext', '出版社:name=CQJTU'), ('author', "作者:['ADSD']"), ('ext
_info', '出版社:CQJTU')])]
额外字段的新增方法主要有两种,一种是通过定义数据模型@property装饰器的方法来指定仅可读方法,这种方法中若定义时与额外字段相同则不需要指定
source
,反之;还有一种就是在序列化模型类中定义方法来修改,通过定义以get_额外字段名
的函数名方法来进行改下。
模型关系分为一对一、多对一和多对多三种,当我们想从一个模型中获取相关联的模型的数据时,也可大致分为三种方式,获取关联模型的主键(
外键名_id
、PrimaryKeyRelatedField
)、获取模型对应的__str__
方法返回的值(StringRelatedField
,用的较少)、还有就是获取关联模型的所有字段(将想要获取关联模型进行序列化后,然后在另外一个序列化类中利用显示出来即可),最后一种就是前面的额外字段的方法,但是有一定的局限性,有些情况不能很好的显示出来,但也可以实现。
外键名_id
方式获取对应的外键 id
# serializers.py
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
created_time = serializers.DateField()
# 在 Django ORM 中,我们知道数据库中保存时为外键_id
publish_id = serializers.IntegerField()
PrimaryKeyRelatedField
,使用时需要添加read_only
或者queryset
# serializers.py
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
created_time = serializers.DateField()
# 使用 PrimaryKeyRelatedField 应注意与模型里面的字段保持一致,
# 并且通常需要设置 `get_queryset`, or set read_only=`True`,否则报错
# publish = serializers.PrimaryKeyRelatedField(queryset=Publish.objects.all())
publish = serializers.PrimaryKeyRelatedField(read_only=True)
In [1]: from book.serializers import BookSerializer
In [2]: from book.models import Book
In [3]: books = Book.objects.all()
In [4]: sers = BookSerializer(books,many=True)
In [5]: sers.data
Out[5]: [OrderedDict([('title', 'Python'), ('created_time', '2021-10-08'), ('publish', 1)]), OrderedDict([('title', 'Vue'), ('created_time', '2021-10-08
'), ('publish', 1)])]
__str__
方法# serializers.py
... 同上
# 获取出版社__str__方法返回的信息
publish = serializers.StringRelatedField()
In [1]: from book.serializers import BookSerializer
In [2]: from book.models import Book
In [3]: books = Book.objects.all()
In [4]: sers = BookSerializer(books,many=True)
In [5]: sers.data
Out[5]: [OrderedDict([('title', 'Python'), ('created_time', '2021-10-08'), ('publish', 'CQJTU')]), OrderedDict([('title', 'Vue'), ('created_time', '2021
-10-08'), ('publish', 'CQJTU')])]
step1:
定义被获取关联模型的序列化字段信息step2:
在需要获取关联模型的序列劣化字段你信息,并用外键名来实例化step1
序列化的模型class PublishSerializer(serializers.Serializer):
publish = serializers.CharField(max_length=32)
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=32)
created_time = serializers.DateField()
# 使用 PrimaryKeyRelatedField 应注意与模型里面的字段保持一致,
# 并且通常需要设置 `get_queryset`, or set read_only=`True`,否则报错
# publish = serializers.PrimaryKeyRelatedField(queryset=Publish.objects.all())
# publish = serializers.PrimaryKeyRelatedField(read_only=True)
# 获取出版社__str__方法返回的信息
publish = PublishSerializer()
Django ORM
模型中学到,外键在数据库中保存的名自动加了_id
,因此正向查询时就可以通过此来获取外键的主键了。通常情况下使用外键关联时,无须反序列化可以都设置为read_only=True
。在多对多时需要指定many=True
,同查询集。
反向查询可以通过
模型名小写_set
来获取相对应得查询集,这里除了一对一关系不需要指定many=True
,其余都需要指定many=True
。一对一不需要加_set
哦,小写表名就可以啦。
官方字段及参数详情地址
选项参数
参数名称 | 作用 |
---|---|
max_length | 最大长度 32 |
min_lenght | 最小长度 2 |
allow_blank | 是否允许为空 False |
trim_whitespace | 是否截断空白字符 True |
max_value | 最小值 0 |
min_value | 最大值 100 |
通用参数
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段是否必须传,在反序列化时必须输入,默认True。 |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
反序列化:从前端获取数据、序列化器的
data
、调用序列化器的is_valid()
方法来叫校验、调用序列化器的save()
方法、最后再进行序列化
json
字典数据data
参数传参(需要以关键字参数进行传参)is_valid(raise_excption=True)
进行校验,若校验出错自动抛出错误信息save()
方法,调用save
时会判断当初始序列化器中是否传入了instance
instance
也传入了data
,那么调用save方法实际调用的就是序列化器中的update
方法,若只有data
则是调用序列化器中的create
方法ser.data
获取在序列化中通过设置参数,如长度等
title = serializers.CharField(max_length=32)
自定义方法有三种形式,可以组合起来使用:
- validate(联合校验,全部字段自定义校验,定义的方法函数名,位于序列化类中)
- validate_字段名(局部校验,校验该字段名的数据,定义的方法函数名,位于序列化类中,一般就用联合校验就顺便把局部校验做了)
- validators(字段参数,定义的方法函数名可以任意,位于序列化类外,使用方法通过在字段中validators=[method1,method2])
from rest_framework import serializers
def about_publish(value):
if 'django' not in value.lower():
raise serializers.ValidationError("未含有Django!")
return value
class PublishSerializer(serializers.Serializer):
publish = serializers.CharField(max_length=32,validators=[about_publish])
datetime = serializers.SerializerMethodField(read_only=True)
def get_datetime(self,obj):
# 额外参数
import datetime
return f'{datetime.datetime.now()}'
def validate(self, attrs):
if '出版社' not in attrs['publish'].lower():
raise serializers.ValidationError("未含有出版社!")
return attrs
验证数据成功后,用序列化器来完成数据反序列化,把数据转成模型类对象,通过实现
create()
和update()
两个方法来实现。如果创建序列化器对象的时候,没有传递instance
实例,则调用save()
方法的时候,create()
被调用;如果传递了instance
实例,则调用save()
方法的时候,update()
被调用。
from rest_framework import serializers
def about_publish(value):
if 'django' not in value.lower():
raise serializers.ValidationError("未含有Django!")
return value
class PublishSerializer(serializers.Serializer):
publish = serializers.CharField(max_length=32,validators=[about_publish])
datetime = serializers.SerializerMethodField(read_only=True)
def get_datetime(self,obj):
# 额外参数
import datetime
return f'{datetime.datetime.now()}'
def validate(self, attrs):
if '出版社' not in attrs['publish'].lower():
raise serializers.ValidationError("未含有出版社!")
return attrs
def create(self, validated_data):
# 新增数据
publish = Publish.objects.create(**validated_data)
return publish
def update(self, instance, validated_data):
# 更新数据,这里的instance就是传入的install = 模型.objects.get(id=1) (obj模型对象)
instance.publish = validated_data["publish"]
instance.save()
return instance
In [11]: from book.serializers import PublishSerializer
In [12]: from book.models import Publish
In [13]: data = {
...: "publish":"Django出版社DRF"
...: }
In [14]: ser = PublishSerializer(data=data)
In [15]: ser.is_valid(raise_exception=True)
Out[15]: True
In [16]: ser.save()
Out[16]: <Publish: Django出版社DRF>
In [17]: ser.data
Out[17]: {'publish': 'Django出版社DRF', 'datetime': '2021-10-09 10:03:09.150345'}
In [18]: [i.publish for i in Publish.objects.all())
File "" , line 1
[i.publish for i in Publish.objects.all())
^
SyntaxError: closing parenthesis ')' does not match opening parenthesis '['
# 可以看到新增成功
In [19]: [i.publish for i in Publish.objects.all()]
Out[19]: ['CQJTU', 'Djangosa出版社', 'Djangosa出版社', 'Django出版社DRF']
In [1]: from book.models import Publish
# 修改前
In [2]: [i.publish for i in Publish.objects.all()]
Out[2]: ['CQJTU', 'Djangosa出版社', 'Djangosa出版社', 'Django出版社DRF']
# 指定修改哪一个
In [3]: pub = Publish.objects.get(pk=1)
In [4]: from book.serializers import PublishSerializer
In [5]: ser = PublishSerializer(instance=pub,data={'publish':'CQJTU出版社Django'})
In [6]: ser.is_valid()
Out[6]: True
In [7]: ser.save()
Out[7]: <Publish: CQJTU出版社Django>
In [8]: ser.data
Out[8]: {'publish': 'CQJTU出版社Django', 'datetime': '2021-10-09 10:10:28.303865'}
# 修改后
In [9]: [i.publish for i in Publish.objects.all()]
Out[9]: ['CQJTU出版社Django', 'Djangosa出版社', 'Djangosa出版社', 'Django出版社DRF']
# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=request.user)
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
ModelSerializer
继承自Serializer
create
和update
方法Serializer
来重写一些自定义方法来校验class BookModelSerializer(serializers.ModelSerializer):
ext = serializers.CharField()
class Meta:
''' 指定需要序列化模型'''
model = Book
''' 指定模型中需要序列化的字段
新增字段需要加上在后面加上
'''
# 模型中所有字段
# fields = '__all__'
# 模型中部分字段
# fields = ['title','created_time','ext']
''' 排除模型中需要序列化的字段
新增字段不需要加上
'''
# 除了 title 不需要其他全都需要(包括新增字段)
exclude = ['title',]
'''修改字段里面的参数'''
# 当生成自动的参数不满足需求时,当然也可以自定方法来进行校验,方法同 Serializer
# 此处不可修改 read_only = True
extra_kwargs = {
'title':{
'write_only':True,
'max_length':32,
},
'created_time':{
'format':"%Y-%m-%d %H:%M:%S"
}
}
'''指定哪些字段只做序列化'''
read_only_fields = ["created_time"]
# 额外参数
def get_ext(self,obj):
return f'其他参数:{obj.title}'
# 自定义方法校验
def validate(self, attrs):
if 'django' not in attrs["title"].lower():
raise serializers.ValidationError("书名没有包含有Django")
return attrs
Serializer
不仅仅是可用于校验数据存储,还可以用于存于无数据模型中如redis
等的校验,而ModelSerializer
仅适用于有数据模型时使用。