1.序列化类常用字段和字段参数
1.1 常用字段类
1.BooleanField
2 NullBooleanField
3 CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
4 EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
5 RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
6 SlugField SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
7 URLField URLField(max_length=200, min_length=None, allow_blank=False)
8 UUIDField UUIDField(format=’hex_verbose’) format: 1)
9 IPAddressField IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
10 IntegerField IntegerField(max_value=None, min_value=None)
11 FloatField FloatField(max_value=None, min_value=None)
12 DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
13 DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
14 DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
15 TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
16 DurationField DurationField()
17 ChoiceField ChoiceField(choices) choices与Django的用法相同
18 MultipleChoiceField MultipleChoiceField(choices)
19 FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
20 ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
1.2重要字段类型
CharField
IntegerField
DecimalField
DateTimeField
BooleanField
ListField
DictField
1.3 常用字段参数
1.CharField及其子类(哪些类的父类是CharField需要在源码中查看)的字段参数:
max_length:最大长度
min_length:最小长度
allow_blank:是否允许为空
trim_whitespace 是否截断空白字符
2.InterField参数:
max_value:最大值
min_value:最小值
3.所有字段都有的的参数:
required:表明该字段在反序列化时必须输入,默认True
default:反序列化时使用的默认值
allow_null:表名该字段是否允许传入None,默认Flase
validators:该字段使用的验证器
error_messages:包含错误编号与错误信息的字典
label:用于HTML展示API页面时,显示的字段名称
help_text:用于HTML展示API页面时,显示的字段帮助提示信息
read_only:表明该字段仅用于序列化输出,默认Flase
write_only:表明该字段仅用于反序列化的输入,默认Flase
4.反序列化校验执行流程:
1.先执行字段自身的校验规则:max_length,max_value
2.再执行验证器validators
3.局部钩子校验规则
4.全局钩子校验规则
2.序列化高级用法之source
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')
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):
# 自有字段,直接点名字,通过sourse可以指定models.py中某张表的字段
name_zzz = serializers.CharField(max_length=8,source='name')
real_price = serializers.CharField(source='price')
# 一对多,需要先点外键名到那张表,再点那张表的名字
publish = serializers.CharField(source='publish.name')
# 多对多,不能用sourse
authors = serializers.CharField()
views.py:
from app01.serializer import BookSerializer
from .models import Book
from rest_framework.response import Response
from rest_framework.views import APIView
class BookView(APIView):
def get(self,request):
book_queryset = Book.objects.all()
ser = BookSerializer(instance=book_queryset,many=True)
return Response(ser.data)
"""
通过以上代码演示效果:在serializer.py中无论字段名起什么,只要括号中的source对应models某张表中的某些字段名,在前端就可以显示该名字。它们之间在views.py中通过视图类连接。
"""
3.序列化高级用法之定制字段的两种方式
以上代码存在局限性:首先我们查到出版社,但是我们只能拿到出版社姓名,无法拿到出版社其他信息,其次多对多关系的作者信息我们没法拿到。我们需要通过以下方法来解决。
3.1SerializerMethodField定制
SerializerMethodField是一个定制返回格式的字段类型,该字段类型中不需要填写任何参数,但是方法需要通过写函数来定制指定的返回的格式。返回的数据遵循restful规范:一对多显示字典,多对多显示列表套字典。
serializer.py:
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name_zzz = serializers.CharField(max_length=8, source='name')
real_price = serializers.CharField(source='price')
publish_detail = serializers.SerializerMethodField()
# 函数名要和字段名保持一致,该字段名也是前端展示的字段名
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'addr': obj.publish.addr}
author_list = serializers.SerializerMethodField()
def get_author_list(self,obj):
l = []
for author_obj in obj.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l
models.py以及views.py代码和上步一样。
3.2在表模型中定制
moodels.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')
# 在表模型中定制的函数名要和serializer.py中的字段名保持一致。
@property
def publish_detail(self):
return {'name':self.publish.name,'addr':self.publish.addr}
# 定制的函数要用@property修饰,可以将方法伪装成一个数据。
@property
def author_list(self):
l = []
for author_obj in self.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l
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)
seriializer.py:
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name_zzz = serializers.CharField(max_length=8, source='name')
real_price = serializers.CharField(source='price')
publish_detail = serializers.DictField()
author_list = serializers.ListField()
4.多表关联反序列化保存
4.1 反序列化字段校验步骤
1.字段自己的:name = serializers.CharField(max_length=8, error_messages={'max_length': '太长了'})
2.validators=[方法](使用频率较低)
3.局部钩子
4.全局钩子
4.2 新增图书接口
# 前端传入数据的格式:{"name":"新阿q正传","price":"88.66","publish":1,"authors":[2]}
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):
return {'name':self.publish.name,'addr':self.publish.addr}
@property
def author_list(self):
l = []
for author_obj in self.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l
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)
seriializer.py:
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.Serializer):
# name和price即用来做序列化,也用来做反序列化,既读又写,所以不用加read_only,write_only
name = serializers.CharField(max_length=8)
price = serializers.CharField()
# 用来做序列化,所以要加上read_only=True
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 用来做反序列化,要加上write_only=True,如果不加会在前端看到该字段
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
# 新增要重写create方法
def create(self, validated_data):
# print(validated_data) {'name': '阿q正传', 'price': '66.66', 'publish': '1', 'authors': [1, 2]}
# 因为前端上传的是publish的id,所以需要用publish_id=validated_data.get('publish')来新增,如果是对象可以直接用publish新增
# 取数据的键需要和前端传过来字典的键保持一致
book_obj = Book.objects.create(name=validated_data.get('name'),price=validated_data.get('price'),publish_id=validated_data.get('publish'))
# 第三张表要手动写代码新增,一个*数打散列表,两个*用来打散字典
book_obj.authors.add(*validated_data.get('authors'))
return book_obj
views.py:
class BookView(APIView):
def get(self,request):
book_queryset = Book.objects.all()
ser = BookSerializer(instance=book_queryset,many=True)
return Response(ser.data)
def post(self,request):
# print(request.data)
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'})
else:
return Response({'code':101,'msg':ser.errors})
前端数据上传尽量使用JSON格式,发现数据新增成功:
4.3 修改图书接口
# 前端传入数据的格式:{"name":"新阿q正传","price":"88.66","publish":1,"authors":[2]}
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):
return {'name':self.publish.name,'addr':self.publish.addr}
@property
def author_list(self):
l = []
for author_obj in self.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l
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)
views.py:
class BookDetailView(APIView):
def put(self,request,pk):
book_obj = Book.objects.filter(pk=pk).first()
ser = BookSerializer(data=request.data,instance=book_obj)
if ser.is_valid():
# save需要手动在BookSerializer类中写update方法
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 = serializers.CharField(max_length=8)
price = serializers.CharField()
# 用来做序列化
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 用来做反序列化
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
def create(self, validated_data):
print(validated_data)
book_obj = Book.objects.create(name=validated_data.get('name'),price=validated_data.get('price'),publish_id=validated_data.get('publish'))
book_obj.authors.add(*validated_data.get('authors'))
return book_obj
def update(self, instance, validated_data):
# print(validated_data) # {'name': '新阿q正传', 'price': '88.66', 'publish': '1', 'authors': [2]}
# uodate方法中instance就是book对象
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish_id = validated_data.get('publish')
#多对多关系在第三张表上,最好先删除,再写入
instance.authors.clear()
instance.authors.add(*validated_data.get('authors'))
# update方法写完依旧要用修改后的对象点save(),然后返回
instance.save()
return instance
5.ModelSerializer使用
ModelSerializer继承自Serializer,完成了很多操作,是之前BookSerializer的简化版:
-跟表模型强关联
-大部分请求,不用写create和update了
serializer.py:
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
# 和Book表绑定
model = Book
# 中括号内的字段名要和extra_kwargs中的字段名保持一致,并且和models.py中的Book表中的字段名保持一致。
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
# 定制限制信息
extra_kwargs = {
'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True}
}
# 写钩子函数,要和class Meta:保持相同的缩进
def validate_name(self, name):
if name.startswith('sb'):
raise ValidationError('不能sb')
else:
return name
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):
return {'name':self.publish.name,'addr':self.publish.addr}
@property
def author_list(self):
l = []
for author_obj in self.authors.all():
l.append({'name':author_obj.name,'phone':author_obj.phone})
return l
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)
views.py:
from app01.serializer import BookSerializer
from .models import Book
from rest_framework.response import Response
from rest_framework.views import APIView
class BookView(APIView):
def get(self,request):
book_queryset = Book.objects.all()
ser = BookSerializer(instance=book_queryset,many=True)
return Response(ser.data)
def post(self,request):
# print(request.data)
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'})
else:
return Response({'code':101,'msg':ser.errors})
class BookDetailView(APIView):
def put(self,request,pk):
book_obj = Book.objects.filter(pk=pk).first()
ser = BookSerializer(data=request.data,instance=book_obj)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'修改成功'})
else:
return Response({'code':101,'msg':ser.errors})