爲什麼要序列化組件?
當我們做前後端分離的項目~~我們前後端交互一般都選擇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])
# 。。。。。。