一、为什么要用序列化和反序列化
前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式。
那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到的数据进行序列化。
二、Serializer序列化
序列化
serializers.py
将models中的字段用Serializer写出来
from rest_framework import serializers
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
pub_time = serializers.DateField()
category = serializers.CharField(source="get_category_display")
#source后面可以跟ORM查询语句
publisher = PublisherSerializer()
authors = AuthorSerializer(many=True) #多对多
views.py
from django.shortcuts import render
from rest_framework.views import APIView #继承的类
from rest_framework.response import Response #返回的方法
from djangoDemo.models import Book #models
from .serializers import BookSerializer #序列化器
class BookView(APIView):
def get(self, request):
book_queryset = Book.objects.all()
# 用序列化器进行序列化
ser_obj = BookSerializer(book_queryset, many=True) #含有多对多字段
return Response(ser_obj.data) #数据存储在data中
def post(self, request):
pass
反序列化
serializers.py
# serializers.py 文件
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False) #不展示,不写入
title = serializers.CharField(max_length=32)
pub_time = serializers.DateField()
category = serializers.CharField(source="get_category_display", read_only=True)
post_category = serializers.IntegerField(write_only=True)
publisher = PublisherSerializer(read_only=True)#只读
# 内部通过外键关系的id找到了publisher_obj
authors = AuthorSerializer(many=True, read_only=True)
publisher_id = serializers.IntegerField(write_only=True) #只写
author_list = serializers.ListField(write_only=True)
def create(self, validated_data):
# validated_data 校验通过的数据 就是book_obj
# 通过ORM操作给Book表增加数据
print(validated_data)
book_obj = Book.objects.create(title=validated_data["title"], pub_time=validated_data["pub_time"],
category=validated_data["post_category"],
publisher_id=validated_data["publisher_id"])
print(book_obj)
book_obj.authors.add(*validated_data["author_list"])
return book_obj
views.py
from . import models
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer
class RestTest(APIView):
def get(self, request):
book_queryset = models.Book.objects.all()
ser_obj = BookSerializer(book_queryset, many=True)
return Response(ser_obj.data)
def post(self, request):
print(request.data) # 接收到的数据
serializer = BookSerializer(data=request.data)
if serializer.is_valid(): # 验证字符合法性
serializer.save()
return Response(serializer.validated_data)
else:
return Response(serializer.errors)
三、ModelSerializer序列化
类似于ModelForm的用法
– 它会根据模型自动生成一组字段
– 它简单的默认实现了.update()以及.create()方法
1. 定义一个序列化器
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# fields = ["id", "title", "pub_time"]
# exclude = ["user"]
# 分别是所有字段 包含某些字段 排除某些字段
depth = 1
# depth 代表找嵌套关系的第几层,使用depth之后只能序列化数据不能反序列化数据
read_only_fields = ["id"]
extra_kwargs = {"publisher": {"write_only": True}, "authors":{"write_only": True}}
#给字段附加属性
2. 附加字段或者覆盖字段
class BookSerializer(serializers.ModelSerializer):
categorys = serializers.CharField(source="get_category_display", read_only=True)
class Meta:
model = Book
fields = "__all__"
3. 由于depth会让外键等字段变为可读的,所以我们必须重新定义一个序列化器,将写和读分开处理,重写读的方法。
serializers.py
class BookSerializer(serializers.ModelSerializer):
"""
读和写不一致的情况下,重新读,重新定义读出来的值的方法为SerializerMethodField,
"""
category_display = serializers.SerializerMethodField(read_only=True)
publisher_info = serializers.SerializerMethodField(read_only=True)
authors_info = serializers.SerializerMethodField(read_only=True)
# get+字段名,为钩子函数,返回值为定义的字段的值,obj为Book_obj对象
def get_category_display(self, obj):
# obj 就是序列化的每个Book对象
return obj.get_category_display()
def get_authors_info(self, obj):
authors_querset = obj.authors.all()
return [{"id": author.id, "name": author.name} for author in authors_querset]
def get_publisher_info(self, obj):
publisher_obj = obj.publisher
return {"id": publisher_obj.id, "title": publisher_obj.title}
class Meta:
model = Book
fields = "__all__"
# exclude=["id"]
# 会让你这些所有的外键关系变成read_only = True
# depth = 1
#将原本的字段设置为只写模式,所以只能写入对应的id
extra_kwargs = {"publisher": {"write_only": True}, "authors": {"write_only": True},
"category": {"write_only": True}}
views.py
from . import models
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer
class RestTest(APIView):
def get(self, request):
book_queryset = models.Book.objects.all()
ser_obj = BookSerializer(book_queryset, many=True)
return Response(ser_obj.data)
def post(self, request):
print(request.data) # 接收到的数据
serializer = BookSerializer(data=request.data)
if serializer.is_valid(): # 验证字符合法性
serializer.save()
return Response(serializer.validated_data)
else:
return Response(serializer.errors)
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'book/', views.RestTest.as_view()),
]
4. 更新局部字段
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'book/', views.RestTest.as_view()),
url(r'edit/(?P<book_id>\d+)/$', views.RestPut.as_view()),
]
views.py
class RestPut(APIView):
def get(self, request, book_id):
book_obj = models.Book.objects.filter(id=book_id).first()
ser_obj = BookSerializer(book_obj)
return Response(ser_obj.data)
# request.data为post发送的数据
def put(self, request, book_id):
book_obj = models.Book.objects.filter(id=book_id).first()
ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
# partial为局部更新
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.validated_data) #验证过的数据
return Response(ser_obj.errors)
四、验证功能
- 单个字段验证
在serializers.py中的类下加入以下方法,验证title字段
def validate_title(self, value):
if "python" not in value.lower():
raise serializers.ValidationError("标题必须含有Python")
return value
- 多个字段验证
# 对多个字段进行验证 要求上架日期不能早于出版日期 上架日期要大
def validate(self, attrs):
if attrs["pub_time"] > attrs["date_added"]:
raise serializers.ValidationError("上架日期不能早于出版日期")
return attrs