什么是序列化与反序列化
序列化
把模型对象转化成字典,经过 Respon 变成json字符串
反序列化
把客户端发送过来的数据,经过 request 变成字典,序列化器可以把字典转化成模型
序列化类Serializer使用
serializer.py
from rest_framework import serializersfrom .models import Bookclass BookSerializer(serializers.Serializer):name = serializers.CharField(max_length=32, min_length=3, allow_blank=False, trim_whitespace=True)price = serializers.IntegerField()publish = serializers.CharField(max_length=32, min_length=3, allow_blank=False, trim_whitespace=True)author = serializers.CharField(max_length=32, min_length=3, allow_blank=False, trim_whitespace=True)def create(self, validated_data):return Book.objects.create(**validated_data)def update(self, instance, validated_data):# instance.name = validated_data.get('name', instance.name)# instance.price = validated_data.get('price', instance.price)# instance.publish = validated_data.get('publish', instance.publish)# instance.author = validated_data.get('author', instance.author)for k, v in validated_data.items():setattr(instance, k, v)instance.save()return instance
views.py
class BookAPIView(APIView):def get(self, request):books = Book.objects.all()ser = BookSerializer(instance=books, many=True)return Response(ser.data)def post(self, request):# data = request.datadata = json.loads(request.body)ser = BookSerializer(data=data)# 校验数据是否合法if ser.is_valid():# 记得保存ser.save()return Response(ser.data)def put(self, request):# data = request.datadata = json.loads(request.body)name = data.get('name')book = Book.objects.filter(name=name).first()ser = BookSerializer(book, data=data)if ser.is_valid():ser.save()return Response(ser.data)class BookDetailView(APIView):def get(self, request, cid):book = Book.objects.filter(pk=cid).first()ser = BookSerializer(instance=book)return Response(ser.data)def delete(self, request, cid):book = Book.objects.filter(pk=cid).first()if book:book.delete()ser = BookSerializer(instance=book)return Response(ser.data)
models.py
class Book(models.Model):name = models.CharField(max_length=32)price = models.IntegerField()publish = models.CharField(max_length=32)author = models.CharField(max_length=32)
url
from django.contrib import adminfrom django.urls import pathfrom app01 import viewsurlpatterns = [path('admin/', admin.site.urls),path('books/', views.BookAPIView.as_view()),path('books/<int:cid>/', views.BookDetailView.as_view()),path('index/', views.BookView.as_view()),]
序列化字段类型和字段参数
字段类型
| 字段 | 字段构造方式 |
|---|---|
| BooleanField | BooleanField() |
| NullBooleanField | NullBooleanField() |
| CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
| EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
| RegexField | RegexField(regex, max_length=None , min_length=None, allow_blank=False) |
| SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
| URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
| UUIDField | UUIDField(format=’hex_verbose’) format: 1. 'hex_verbose'如 "5ce0e9a5-5ffa-654b-cee0-1238041fb31a"2. 'hex'如 "5ce0e9a55ffa654bcee01238041fb31a"3. 'int'- 如: "123456789012312313134124512351145145114"4. 'urn'如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
| IPAddressField | IPAddressField(protocol=’both’, unpack_ipv4=False, **options) |
| IntegerField | IntegerField(max_value=None, min_value=None) |
| FloatField | FloatField(max_value=None, min_value=None) |
| DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
| DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
| DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
| TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
| DurationField | DurationField() |
| ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
| MultipleChoiceField | MultipleChoiceField(choices) |
| FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
| ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
| ListField | ListField(child=, min_length=None, max_length=None) |
| DictField | DictField(child=) |
字段参数
| 参数 | 说明 |
|---|---|
max_length |
最大长度 |
min_length |
最小长度 |
max_value |
最大值 |
min_value |
最小值 |
allow_blank |
是否允许为空 |
trim_whitespace |
是否截断空白字符 |
| read_only | 表明该字段仅用于序列化输出,默认False(只能查看,不能修改) |
| write_only | 表明该字段仅用于反序列化输入,默认False(只能修改,不能查看) |
default |
反序列化时使用的默认值 |
allow_null |
表明该字段是否允许传入None,默认 False |
validators |
该字段使用的验证器 |
error_messages |
包含错误编号与错误信息的字典 |
label |
用于HTML展示API页面时,显示的字段名称 |
| `help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
序列化器的字段校验功能
字段自带的校验规则
class BookSerializer(serializers.Serializer):id = serializers.IntegerField(required=False)title = serializers.CharField(max_length=32)price = serializers.DecimalField(max_digits=6, decimal_places=2)publisher = serializers.CharField(max_length=32)
validators的校验
# validators的校验,类似于局部钩子def check(data):if len(data) > 10:raise ValidationError('最长不能超过10')return dataclass BookSerializer(serializers.Serializer):id = serializers.IntegerField(required=False)title = serializers.CharField(max_length=32)price = serializers.DecimalField(max_digits=6, decimal_places=2)publisher = serializers.CharField(max_length=32, validators=[check, ]) # 在这里用:validators=[check, ],可以放在一个列表中
局部钩子与全局钩子
# 局部钩子:validate_字段名def validate_age(self, age):if int(age) > 100:raise ValidationError('年龄不能大于100')return age# 全局钩子def validate(self, attrs):name = attrs.get('name')age = attrs.get('age')if age == name:raise ValidationError('年龄和名字不能相同')return attrs
序列化类ModelSerializer
class BookSerializer(serializer.ModelSerializer):class Meta:model = 表模型 # 跟哪个表模型建立关系fields = ['字段1', '字段2'] # 序列化的字段,反序列化的字段fields = '__all__' # 所有字段都序列化,反序列化exclude=['字段1','字段2'] # 排除哪些字段(不能跟fields同时使用)read_only_fields=['price','publish'] # 序列化显示的字段write_only_fields=['title'] # 反序列化需要传入的字段extra_kwargs ={'title':{'max_length':32,'write_only':True}}depth=1 # 跨表查询1次,最多建议写3# 表示重写name这个字段,会走它的规则name = serializers.CharField(max_length=32,min_length=3)
注意:
- 局部全局钩跟之前没有任何区别
create和update不需要写了(内部已经写好了)- 可以重写某个字段,注意缩进
多表序列化
方法名叫get_字段名,返回值就是要显示的东西
方式一
重写字段+必须配合一个方法,方法返回什么,该字段就是什么(该字段只能序列化)
class BookSerializer(serializers.ModelSerializer):class Meta:model = Bookfields = ['nid', 'name', 'price', 'publish_detail', 'author_detail', 'publish', 'authors']# depth = 1extra_kwargs = {'publish': {'write_only': True},'authors': {'write_only': True},}publish_detail = serializers.SerializerMethodField(read_only=True)def get_publish_detail(self, obj):return {'name': obj.name, 'city': obj.publish.city}author_detail = serializers.SerializerMethodField(read_only=True)def get_author_detail(self, obj):author_list = []for author in obj.authors.all():author_list.append({'name': author.name, 'addr': author.author_detail.addr})return author_list
方式二
在表模型models中写方法,在序列化类中写到fields中
