目录
1、3 示例3:基于ModelSerializer(含FK+M2M):
1、单个序列化post或get(单个)请求(UserModelSerializer(data=request.data))
2、多个序列化get请求(UserModelSerializer(instance=queryset, many=True))
drf中为我们提供了Serializer,他主要有两大功能:
-
对请求数据校验(底层调用Django的Form和ModelForm)
-
对数据库查询到的对象进行序列化
1、数据校验(Serializer)
1、1 示例1:基于Serializer:
import re
from django.core.validators import EmailValidator
from rest_framework import exceptions
from rest_framework import serializers
class RegexValidate:
def __init__(self, base):
self.base = base
# 类被调用时,执行改方法
def __call__(self, value):
macth_obj = re.match(self.base, value)
if not macth_obj:
raise serializers.ValidationError("格式错误")
class MySerializers(serializers.Serializer):
username = serializers.CharField(label="姓名", max_length=10, min_length=5, required=True)
age = serializers.IntegerField(label="年龄", max_value=100, min_value=0, required=True)
level=serializers.ChoiceField(label="级别",choices=models.UserInfo.level_choices)
# 邮箱校验方式一
email1 = serializers.EmailField(label="邮箱校验方式一")
# 邮箱校验方式二
email2 = serializers.CharField(label="邮箱校验方式二", validators=[RegexValidate(r"^\w+@\w+\.\w+$"), ])
# 邮箱校验方式三
email3 = serializers.CharField(label="邮箱校验方式三")
def validate_email3(self, value):
if re.match(r"^\w+@\w+\.\w+$", value):
return value
raise exceptions.ValidationError("格式错误")
1、2 示例2:基于ModelSerializer:
import re
from django.core.validators import EmailValidator
from rest_framework import exceptions
from rest_framework import serializers
class RegexValidate:
def __init__(self, base):
self.base = base
# 类被调用时,执行改方法
def __call__(self, value):
macth_obj = re.match(self.base, value)
if not macth_obj:
raise serializers.ValidationError("格式错误")
class MySerializers(serializers.ModelSerializer):
age = serializers.IntegerField(label="年龄", max_value=100, min_value=0, required=True)
level = serializers.ChoiceField(label="级别", choices=models.UserInfo.level_choices)
# 邮箱校验方式一
email1 = serializers.EmailField(label="邮箱校验方式一")
# 邮箱校验方式二
email2 = serializers.CharField(label="邮箱校验方式二", validators=[RegexValidate(r"^\w+@\w+\.\w+$"), ])
# 邮箱校验方式三
email3 = serializers.CharField(label="邮箱校验方式三")
class Meta:
model = models.UserInfo
fields = ["username", "age", "level", "email1", "email2", "email3"]
extra_kwargs = {
"username": {"max_length": 10, "min_length": 5}
}
def validate_email3(self, value):
if re.match(r"^\w+@\w+\.\w+$", value):
return value
raise exceptions.ValidationError("格式错误")
1、3 示例3:基于ModelSerializer(含FK+M2M):
class Meta:
model = models.UserInfo
fields = ["level", "roles"]
extra_kwargs = {
"username": {"max_length": 10, "min_length": 5}
}
参考:Meta:是MySerializers(serializers.ModelSerializer)下定义的
这是你在传参时,必须带上level和roles,这是你就必须要用json格式来发送数据
{"level":1,"roles",[1,2]}
2 、序列化
通过ORM从数据库获取到的 QuerySet 或 对象 均可以被序列化为 json 格式数据。
2、1 示例1:序列化基本字段
class DepartModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Department
fields = ['id', "title"]
# 切记, 如果从数据库获取的不是QuerySet对象,而是单一对象,例如:
data_object = modes.UserInfo.objects.filter(id=2).first()
ser = UserModelSerializer(instance=data_object,many=False)
print(ser.data)
2、2 示例2:自定义字段
class NewsSerializer(serializers.ModelSerializer):
image_list = serializers.SerializerMethodField()
topic_title = serializers.CharField(source="topic.title",)
zone_title = serializers.CharField(source="get_zone_display", )
status = serializers.CharField(source="get_status_display",)
class Meta:
model = models.News
fields = ['id', "title", "url",
'image', 'topic', "zone",
"zone_title", 'image_list', "topic_title", 'collect_count', 'recommend_count', 'comment_count',
"status"]
def get_image_list(self, obj):
if not obj.image:
return []
return obj.image.split(',')
def validate_topic(self, value):
if not value:
return value
request = self.context['request']
exists = models.Topic.objects.filter(deleted=False, id=value.id, user=request.user).exists()
if not exists:
raise ValidationError("话题不存在")
return value
def validate_title(self, value):
url = self.initial_data.get('url')
image = self.initial_data.get('image')
zone = self.initial_data.get('zone')
if url and image:
raise ValidationError("请求数据错误")
if not url and not image:
if zone == 3:
raise ValidationError("分区选择错误")
return value
2、3 示例3:序列化类的嵌套
from rest_framework import serializers
#嵌套1
class IndexSubTopicSerializer(serializers.ModelSerializer):
class Meta:
model = models.Topic
fields = ['id', 'title', 'is_hot']
#嵌套2
class IndexSubUserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = ['id', 'username', ]
class IndexSerializer(serializers.ModelSerializer):
topic = IndexSubTopicSerializer(source=topic)
user = IndexSubUserSerializer(source=user)
class Meta:
fields=["topic","user"]
注意:在嵌套序列化的过程中,后面需要加一个参数,source=当前的对象,如下:
# demo.py
topic = IndexSubTopicSerializer(source=topic)
user = IndexSubUserSerializer(source=user)
3 、数据校验&序列化
上述示例均属于单一功能(要么校验,要么序列化),其实当我们编写一个序列化类既可以做数据校验,也可以做序列化,例如:
from rest_framework import serializers
class NewsSerializer(serializers.ModelSerializer):
image_list = serializers.SerializerMethodField(read_only=True)
topic_title = serializers.CharField(source="topic.title", read_only=True)
zone_title = serializers.CharField(source="get_zone_display", read_only=True)
status = serializers.CharField(source="get_status_display", read_only=True)
# title、url、image、'topic', "zone"
# - 只有title,只创建文本 + 分区不能是图片
# - 有title,image,
# - 有title,url
class Meta:
model = models.News
fields = ['id', "title", "url",
'image', 'topic', "zone",
"zone_title", 'image_list', "topic_title", 'collect_count', 'recommend_count', 'comment_count',
"status"]
read_only_fields = ['collect_count', 'recommend_count', 'comment_count']
extra_kwargs = {
'topic': {'write_only': True}, # 新增时,topic=1
'image': {'write_only': True}, # 图片地址 xxxx,xxxx,xxxx
'zone': {'write_only': True},
}
def get_image_list(self, obj):
if not obj.image:
return []
return obj.image.split(',')
def validate_topic(self, value):
return value
def validate_title(self, value):
return value
注意:
1、read_only=True时,不用校验,必须序列化返回
2、write_only=True时,必须校验,不用序列化返回
3、read_only_fields来制定必须序列化的字段
4、序列化的过程
1、单个序列化post或get(单个)请求(UserModelSerializer(data=request.data))
def post(self, request):
""" 添加用户 """
ser = UserModelSerializer(data=request.data)
if not ser.is_valid():
return Response({'code': 1006, 'data': ser.errors})
ser.validated_data.pop('email2')
instance = ser.save(age=18, password="123", depart_id=1)
# 新增之后的一个对象(内部调用UserModelSerializer进行序列化)
print(instance)
# ser = UserModelSerializer(instance=instance, many=False)
# ser.data
return Response({'code': 0, 'data': ser.data})
save()会返回一个obj对象
2、多个序列化get请求(UserModelSerializer(instance=queryset, many=True))
def get(self, request):
""" 添加用户 """
queryset = models.UserInfo.objects.all()
ser = UserModelSerializer(instance=queryset, many=True)
ser.data #序列化后的数据
return Response({"code": 0, 'data': ser.data})
5、序列化过程中request的处理
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)
#将request添加到context中
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
#servalisers类,将context提取到自己的类中
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super().__init__(**kwargs)
在序列化类中可以通过:
request=self.context["request"]来获取
def validate_topic(self, value):
if not value:
return value
request = self.context['request']
exists = models.Topic.objects.filter(deleted=False, id=value.id, user=request.user).exists()
if not exists:
raise ValidationError("话题不存在")
return value
6、校验过程中校验参数的处理
def validate_title(self, value):
url = self.initial_data.get('url')
image = self.initial_data.get('image')
zone = self.initial_data.get('zone')
if url and image:
raise ValidationError("请求数据错误")
if not url and not image:
if zone == 3:
raise ValidationError("分区选择错误")
return value
通过:
1、url = self.initial_data.get('url')来提取需要校验的值(在ser.is_valid()过程中)
2、ser = UserModelSerializer(data=request.data)
ser.is_valid()校验完成后
ser.validated_data才会有校验的数据
7、read_only和write_only区别
1、read_only只会走instance参数,返回数据,不会走data参数(is_valid),只管返回的事情
1、可以在自定义字段时加入read_only=True,
2、read_only_fields=[]里批量添加,
3、extra_kwargs里设置{"xx":{"read_only":True}}
2、write_only只会走data=(is_valid)参数,校验数据,不会走instance参数,
校验完成后,
ser.save()添加一个对象实例,返回当前对象,
ser.data获取返回的对象实例序列化后的数据(注意:instance=ser,many=False)