第七十一篇 Django rest-framework 序列化和反序列化用法 - Go语言中文社区

第七十一篇 Django rest-framework 序列化和反序列化用法


一、为什么要用序列化和反序列化

前后端交互一般都选择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)

四、验证功能

  1. 单个字段验证
    在serializers.py中的类下加入以下方法,验证title字段
    def validate_title(self, value):
        if "python" not in value.lower():
            raise serializers.ValidationError("标题必须含有Python")
        return value
  1. 多个字段验证
# 对多个字段进行验证 要求上架日期不能早于出版日期 上架日期要大
    def validate(self, attrs):
        if attrs["pub_time"] > attrs["date_added"]:
            raise serializers.ValidationError("上架日期不能早于出版日期")
        return attrs
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_45503700/article/details/105619537
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢