为什么要序列化组件?
当我们做前后端分离的项目~~我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式。
那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到的数据进行序列化。
Django序列化的方法
.values 序列化结果
class BooksView(View):
def get(self, request):
book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
book_list = list(book_list)
# 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的
ret = []
for book in book_list:
pub_dict = {}
pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
pub_dict["id"] = pub_obj.pk
pub_dict["title"] = pub_obj.title
book["publisher"] = pub_dict
ret.append(book)
ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
return HttpResponse(ret)
# json.JSONEncoder.default()
# 解决json不能序列化时间字段的问题
class MyJson(json.JSONEncoder):
def default(self, field):
if isinstance(field, datetime.datetime):
return field.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, datetime.date):
return field.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field)
from django.core import serializers
# 能够得到我们要的效果 结构有点复杂
class BooksView(View):
def get(self, request):
book_list = Book.objects.all()
ret = serializers.serialize("json", book_list)
return HttpResponse(ret)
DRF序列化
首先,我们要用DRF的序列化,就要遵循人家框架的一些标准,
-- Django我们CBV继承类是View,现在DRF我们要用APIView
-- Django中返回的时候我们用HTTPResponse,JsonResponse,render ,DRF我们用Response
序列化
1.声明序列化类
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display")
pub_time = serializers.DateField()
2.序列化对象
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
# 用序列化器去序列化queryset
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
实现流程
-- 如果指定了many=True
-- 把queryset当成可迭代对象去循环 得到每个模型对象
-- 把每个模型对象放入序列号器进行序列化
-- 进行字段匹配 匹配上的字段进行序列化 匹配不上丢弃
-- 必须满足序列化的所有字段要求
外键关系的序列化
# by gaoxin
from rest_framework import serializers
from .models import Book
class PublisherSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=32)
age = serializers.IntegerField()
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
pub_time = serializers.DateField()
publisher = PublisherSerializer(read_only=True)
user = UserSerializer(many=True, read_only=True)
反序列化
当前端给我们发post的请求的时候前端给我们传过来的数据我们要进行一些校验然后保存到数据库,这些校验以及保存工作,DRF的Serializer也给我们提供了一些方法了
首先我们要写反序列化用的一些字段有些字段要跟序列化区分开
Serializer提供了.is_valid() 和.save()方法~~
# serializers.py 文件
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
w_chapter = serializers.IntegerField(write_only=True)
pub_time = serializers.DateField()
publisher = PublisherSerializer(read_only=True)
user = UserSerializer(many=True, read_only=True)
users = serializers.ListField(write_only=True)
publisher_id = serializers.IntegerField(write_only=True)
def create(self, validated_data):
book = Book.objects.create(title=validated_data["title"],
chapter=validated_data["w_chapter"],
pub_time=validated_data["pub_time"],
publisher_id=validated_data["publisher_id"])
book.user.add(*validated_data["users"])
return book
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializer(book_list, many=True)
return Response(ret.data)
def post(self, request):
# book_obj = request.data
print(request.data)
serializer = BookSerializer(data=request.data)
if serializer.is_valid():
print(12341253)
serializer.save()
return Response(serializer.validated_data)
else:
return Response(serializer.errors)
当前端给我们发送patch请求的时候,前端传给我们用户要更新的数据,我们要对数据进行部分验证~~
PATCH请求serializers.py
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
w_chapter = serializers.IntegerField(write_only=True)
pub_time = serializers.DateField()
publisher = PublisherSerializer(read_only=True)
user = UserSerializer(many=True, read_only=True)
users = serializers.ListField(write_only=True)
publisher_id = serializers.IntegerField(write_only=True)
def create(self, validated_data):
book = Book.objects.create(title=validated_data["title"], chapter=validated_data["w_chapter"], pub_time=validated_data["pub_time"],
publisher_id=validated_data["publisher_id"])
book.user.add(*validated_data["users"])
return book
def update(self, instance, validated_data):
instance.title = validated_data.get("title", instance.title)
instance.chapter = validated_data.get("w_chapter", instance.chapter)
instance.pub_time = validated_data.get("pub_time", instance.pub_time)
instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
if validated_data.get("users"):
instance.user.set(validated_data.get("users"))
instance.save()
return instance
class BookView(APIView):
def patch(self, request):
print(request.data)
book_id = request.data["id"]
book_info = request.data["book_info"]
book_obj = Book.objects.filter(pk=book_id).first()
serializer = BookSerializer(book_obj, data=book_info, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
验证
如果我们需要对一些字段进行自定义验证,DRF给我们提供了钩子方法:
单个字段的验证:
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
# 省略了一些字段 跟上面代码里一样的
# 。。。。。
def validate_title(self, value):
if "python" not in value.lower():
raise serializers.ValidationError("标题必须含有Python")
return value
多个字段的验证:
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32)
CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
chapter = serializers.ChoiceField(choices=CHOICES, source="get_chapter_display", read_only=True)
w_chapter = serializers.IntegerField(write_only=True)
pub_time = serializers.DateField()
date_added = serializers.DateField(write_only=True)
# 新增了一个上架时间字段
# 省略一些字段。。都是在原基础代码上增加的
# 。。。。。。
# 对多个字段进行验证 要求上架日期不能早于出版日期 上架日期要大
def validate(self, attrs):
if attrs["pub_time"] > attrs["date_added"]:
raise serializers.ValidationError("上架日期不能早于出版日期")
return attrs
验证器validators
def my_validate(value):
if "敏感词汇" in value.lower:
raise serializers.ValidationError("包含敏感词汇,请重新提交")
return value
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32, validators=[my_validate])
# 。。。。。。