常用字段类和字段参数
1.
CharField
BooleanField
IntegerField
DecimalField
2.返回格式
ListField:
{hobby: ['篮球', '足球']}
DictField:
{wife: {'name': 'barry'}}
| 参数名称 |
作用 |
| max_length |
最大长度 |
| min_lenght |
最小长度 |
| allow_blank |
是否允许为空 |
| trim_whitespce |
是否截断空白字符 |
| max_value |
最小值 |
| min_value |
最大值 |
| 参数名称 |
作用 |
| required |
该字段在反序列化时必须输入,默认为True |
| default |
反序列化时使用的默认值 |
| allow_null |
该字段是否允许传入None,默认为False |
| validators |
该字段使用的验证器 |
| error_messages |
包含错误编号与错误信息的字典 |
| label |
用于HTML展示API页面时,显示的字段名称 |
| help_text |
用于HTML展示API页面时,显示的字段帮助提示信息 |
| read_only |
该字段仅用于序列化输出,默认为False |
| write_only |
该字段仅用于反序列化输入,默认为False |
序列化字段参数sourec的使用
1.name字段在前端显示的时候叫book_name
book_name = serializers.CharField(max_length=8, min_length=3, source='name')
'source字段可以指定序列化表中那个字段'
2.source指定的可以是字段也可以是方法,用于重命名
book_name = serializers.CharField(max_length=8, min_length=3, source='sb_name')
def sb_name(self):
return 'sb' + self.name
'source可以做跨表查询'
表模型和数据录入
-在前端显示
[
{
"name": "西游记",
"price": 30,
"publish": {
"name": "广州出版社",
"city": "广州",
"email": "2@qq.com"
}
}
]
1.方法1:在序列化类中使用SerializerMethodField
publish = serializers.SerializerMethodField()
def get_publish(self, obj):
# obj是当前序列化的对象
return {'name': obj.publish.name,
'city': obj.publish.city,
'email': obj.publish.email}
2.方法2:在表模型中写方法
def publish_detail(self):
return {'name': self.publish.name,
'city': self.publish.city,
'email': self.publish.email}
# 序列化中
publish_detail = serializers.DictField()
'在模型类中写逻辑代码,称之为ddd,领域驱动模型'
多表基于Serializer反序列化
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField(null=True)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
author = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
def publish_detail(self):
return {'name': self.publish.name,
'city': self.publish.city,
'email': self.publish.email}
class BookSerializer(serializers.Serializer):
# 要序列化字段
name = serializers.CharField(max_length=8, min_length=3)
price = serializers.IntegerField(max_value=99, min_value=10)
# 反序列化
publish = serializers.IntegerField(write_only=True)
author = serializers.ListField(write_only=True)
# 序列化
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 要重写create
def create(self, validated_data):
# validated_data是校验后的数据
book = Book.objects.create(name=validated_data.get('name'),
price=validated_data.get('price'),
publish_date=validated_data.get('publish_date'),
publish_id=validated_data.get('publish'))
author = validated_data.get('author')
book.author.add(*author)
return book
ModelSerializer的使用
继承Serializer的序列化类,在序列化的每个字段无论是序列化还是反序列化都要写,如果是新增或修改,都需要重写create、update
'可以使用ModelSerializer来做'
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
# 要序列化的表模型
model = Book
# 所有字段都序列化
# fields = '__all__'
# 列表说什么就序列化那个字段
fields = ['name', 'price', 'publish_date', 'publish', 'author', 'publish_list', 'author_list']
# 给author和publish加write_only属性,给name加max_length属性
extra_kwargs = {'name': {'max_length': 8},
'publish': {'write_only': True},
'author': {'write_only': True},
}
publish_list = serializers.SerializerMethodField(read_only=True)
def get_publish_list(self, obj):
return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}
author_list = serializers.SerializerMethodField(read_only=True)
def get_author_list(self, obj):
res = []
for author in obj.author.all():
res.append({'id': author.id, 'name': author.name, 'age': author.age})
return res
反序列化之数据校验
-使用
1.定义一个类继承ModelSerializer
2.类内部写class Meta:
3.在内部类中指定model,也就是要序列化的表
4.在内部类中指定fields,fields是要序列化的字段,不写fields写__all__表示所有,不包含方法
5.在内部指定extra_kwargs,给字段添加字段参数
6.在序列化类中可以重写某个字段
name = serializers.SerializerMethodField()
def get_name(self, obj):
return 'sb' + obj.name
7.不需要重写create、update
1.反序列化有字段自己的校验规则、局部钩子、全局钩子
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
# 要序列化的表模型
model = Book
# 列表说什么就序列化那个字段
fields = ['name', 'price', 'publish_date', 'publish', 'author']
# 继承ModelSerializer时给name加属性
extra_kwargs = {'name': {'max_length': 8, 'min_length': 3,
'error_messages': {'min_length': "太短了"}},
'price': {'max_value': 100, 'min_value': 3},
'publish': {'write_only': True},
'author': {'write_only': True},
}
# 局部钩子
def validate_name(self, name):
if name.startswith('sb'):
# 校验不通过抛异常
raise ValidationError('不能以sb卡头')
else:
return name
# 全局钩子
def validate(self, attrs):
if attrs.get('name') == attrs.get('publish_date'):
raise ValidationError('名字不能等于日期')
else:
return attrs
反序列化数据校验源码分析
-执行了字段校验ser.is_valid(),在BaseSerializer内的is_valid()方法
def is_valid(self, *, raise_exception=False):
if not hasattr(self, '_validated_data'):
try:
# 真正走的校验,成功后返回校验过后的数据
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
return not bool(self._errors)
'''
-如果你按住ctrl键,鼠标点击,会从当前类中找run_validation,找不到才会去父类找
-按住ctrl键,鼠标点击找到的run_validation不是代码的执行,代码执行要从头开始找,从自己身上在往上找
'''
-内部执行了self.run_validation(self.initial_data),本质执行的Serializer的run_validation
-去self:序列化类的对象中,反射validate_字段名的方法
def run_validation(self, data=empty):
# 局部钩子的执行
value = self.to_internal_value(data)
try:
# 全局钩子的执行,从根上开始找,优先执行自己定义的序列化类中的全局钩子
value = self.validate(value)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
-全局钩子看完了,在看局部钩子,在self.to_internal_value中找,本质执行的Serializer的
def to_internal_value(self, data):
# fields中是序列化类中所有的字段,for循环每次取一个字段对象
for field in fields:
# 反射:去序列化类的对象(self)中,反射 validate_字段名 的方法
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
# 这是字段自己的校验规则
validated_value = field.run_validation(primitive_value)
# 局部钩子
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
return ret
作业
#1 所有人写出book表(带关联关系)5 个接口
Serializer
ModelSerializer(简单,不用重写create和update)
name最大8,最小3,名字中不能带sb
price最小9,最大199,不能为66
#2 出版社,作者,作者详情 5个接口写完(ModelSerializer好些一些
class BookModelSerializer(serializers.ModelSerializer):
# price = serializers.DecimalField()
class Meta:
# 要序列化的表模型
model = Book
# 列表说什么就序列化那个字段
fields = ['name', 'price', 'publish_date', 'publish', 'author']
# 继承ModelSerializer时给name加属性
extra_kwargs = {'name': {'max_length': 8, 'min_length': 3,
'error_messages': {'min_length': "太短了"}},
'price': {'max_value': 199, 'min_value': 9},
'publish': {'write_only': True},
'author': {'write_only': True},
}
# 局部钩子
def validate_name(self, name):
if name.startswith('sb'):
# 校验不通过抛异常
raise ValidationError('不能以sb卡头')
else:
return name
def validate_price(self, price):
if price == 66:
# 校验不通过抛异常
raise ValidationError('不能是66')
else:
return price
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ser = BookModelSerializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = BookModelSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '新增成功'})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDataView(APIView):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookModelSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookModelSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response()