反序列化之updata
视图层
class AddBookView(APIView):
def put(self, request, pk):
book_obj = models.Book.objects.filter(pk=pk).first()
book = BookSerializer(book_obj, data=request.data)
if book.is_valid():
book.save()
return Response({"code": 200, "msg": book.data})
else:
return Response({"code": 101, "msg": book.errors})
序列化
重写updata方法:
def update(self, instance, validated_data):
models.Book.objects.filter(pk=instance.pk).update(**validated_data)
return instance
source的高级用法
字段类中的属性,作用是能修改序列化的字段
方式一:
class BookSerializer(serializers.Serializer):
wayyy = serializers.CharField(source="book_name")
前端接收到的:
{
"wayyy": "西游记",
},
方法二:跨表查询
序列化:
class BookSerializer(serializers.Serializer):
publish_id = serializers.CharField(source="publish.publish_name")
前端接收到的:
{
"publish_id": "东京出版社"
},
方式三:表模型中写方法,在序列化层拿到返回的名字
序列化:
class BookSerializer(serializers.Serializer):
xxx = serializers.CharField(source="get_name")
models层:
def get_name(self):
return self.publish.publish_name
前端接收到的:
{
"wayyy": "西游记",
"book_price": 500,
"xxx": "东京出版社"
}
高级用法定制字段
定制返回的字段格式,一共有三种格式ps(publish也是一个对象)
{
"book_name": "西游记",
"book_price": 500,
"publish": {
"publish_name": "东京出版社",
"publish_addr": "东京"
}
},
第一种:在序列化类使用SerializerMethodField 定制
class BookSerializer(serializers.Serializer):
publish = serializers.SerializerMethodField()
def get_publish(self, obj):# 返回什么,序列化后publish就是什么
# obj就是序列化得到的book对象
return {"publish_name": obj.publish.publish_name, "publish_addr": obj.publish.publish_addr}
第二种:在表模型中定制
models:
# 将方法伪装成属性
@property
def publish_dic(self):
return {"publish_name": self.publish.publish_name, "publish_addr": self.publish.publish_addr}
序列化类:
publish_dic = serializers.DictField()
多表关联序列化和反序列化
# 多表关联序列化和反序列化,要分清楚哪些字段是需要序列化,哪些字段是需要反序列化,哪些字段是即需要序列化又需要反序列化
序列化
from rest_framework import serializers
from app_one import models
class BookSerializer(serializers.Serializer):
# 这两个字段是既要序列化又要反序列化
book_name = serializers.CharField(max_length=8, min_length=1, )
book_price = serializers.IntegerField(max_value=1000, min_value=10)
# 这两个字段只需要序列化:将我自己的数据序列化传给前端
publish_dic = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 这两个字段需要反序列化:反序列化就是将前端传过来的数据进行处理转换成我自己数据
publish_id = serializers.CharField(write_only=True)
author_book = serializers.ListField(write_only=True)
# def validate_book_name(self, value):
# pass
#
# def validate(self, attrs):
# pass
def create(self, validated_data):
authors = validated_data.pop("author_book")
book_data = models.Book.objects.create(**validated_data)
# 增加中间表的记录:图书和作者的关系
book_data.authors.add(*authors)# 向中间表中存入:这个图书关联的做作者
return book_data
def update(self, instance, validated_data):
models.Book.objects.filter(pk=instance.pk).update(**validated_data)
return instance
针对返回的数据格式在models层做的处理
class Book(models.Model):
book_name = models.CharField(max_length=32)
book_price = models.IntegerField()
is_delete = models.IntegerField(default=0)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
@property
def publish_dic(self):
# 出版社的返回信息必须是以字典形式返回
return {"publish_name": self.publish.publish_name, "publish_addr": self.publish.publish_addr}
@property
def author_list(self):
# 图书作者的返回信息以列表形式展现
lis = []
for author in self.authors.all():
lis.append({"author_name": author.username})
return lis
视图层
from django.shortcuts import render
from rest_framework.views import APIView
from .serializers import BookSerializer
from rest_framework.response import Response
from app_one import models
# Create your views here.
class BookView(APIView):
def get(self, request):
book_obj = models.Book.objects.filter(is_delete=0).all()
book = BookSerializer(instance=book_obj, many=True)
return Response(book.data)
def post(self, request):
print(request.data)
book = BookSerializer(data=request.data)
if book.is_valid():
book.save()
return Response({"code": 100, "msg": book.data})
else:
return Response({"code": 101, "msg": book.errors})
class AddBookView(APIView):
def get(self, request, pk):
book_obj = models.Book.objects.filter(pk=pk).filter()
book = BookSerializer(instance=book_obj)
return Response(book.data)
def put(self, request, pk):
book_obj = models.Book.objects.filter(pk=pk).first()
book = BookSerializer(book_obj, data=request.data)
if book.is_valid():
book.save()
return Response({"code": 200, "msg": book.data})
else:
return Response({"code": 101, "msg": book.errors})
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).update(is_delete=1)
return Response({"code": 200, "msg": "删除成功"})
路由层
from django.contrib import admin
from django.urls import path
from app_one.views import BookView, AddBookView
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view()),
path('books/<int:pk>/', AddBookView.as_view()),
]
多表查询序列化及反序列化总结
1、使用之前必须先判断清除哪些字段是用来序列化的,哪些字段是用来反序列化,哪些字段是用来即序列化又反序列化的
1.1、判断完成以后,在只需要序列化的字段里加入参数read_only=True表示该字段仅用于序列化
1.2、在只需要反序列化的字段里加入参数write_only=True表示该字段仅用于反序列化
1.3、如果这两个参数都没写,表示该字段既用于序列化又用于反序列化
2、确定返回给前端的数据是返回什么样的格式,需不需要自定义字段
2.1、在models层自定义字段的时候,方法名要和字段名保持一致
2.2、如果在序列化类里面写定制字段,注意方法名的命名 get_要定制的字段
2.3、在序列化类中定制要使用serializers.SerializerMethodField()
2.4、在models定制返回的如果是字典,序列化类里面定制的字段要用serializers.DictField,如果返回的是列表,要使用erializers.ListField
3、做反序列化校验
# 三层:
字段自己:字段类属性--->可控制的比较小
局部钩子:单个字段校验---->校验反序列化的字段
全局钩子:多个字段同时校验