rest-framework框架之序列化

rest-framework框架之序列化

开发 API 接口最重要的工作就是将代码片段的输出序列化和反序列化为类似于 json 的表示形式。

在 rest-framework 中,通过声明与 Django 中 forms 非常类似的序列化器(serializers)来实现。

用到的 models

from django.db import models


# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField()
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish")
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name

使用 Serializer

Serializer 的学习可以类比 Django 中的 form 。它们都有 CharField ,IntegerField 等。

数据表中的普通字段用 CharField ,IntegerField 等,一对多用 CharField ,里面加上 source 指向要对应的字段。多对多用 SerializerMethodField ,并且自定义一个名为 get_多对多字段名 的函数,此时该多对多字段的值取决于这个函数的返回值。

from app01.models import *
from rest_framework import serializers


class BookSerializers(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    price = serializers.IntegerField()
    pub_date = serializers.DateField()
    # 一对多用CharField,里面加上source
    publish = serializers.CharField(source="publish.name")
    # 多对多用SerializerMethodField
    authors = serializers.SerializerMethodField()

    # 此时authors值取决于下面函数的返回值
    def get_authors(self, obj):
        authors_temp = []
        for authors_obj in obj.authors.all():
            authors_temp.append(authors_obj.name)

        return ",".join(authors_temp)

使用 ModelSerializer

ModelSerializer 可以类比成 Django 中的 ModelForm 它实现的功能与 Serializer 一样,只是代码量更少,功能更多。

普通字段

通过 Meta 类将普通字段转成 Serializer 类中的各种字段。其中, model 绑定的数据表模型,fields 绑定要转化的字段,"__all__" 表示要将所有字段都转成相应的类型。

class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = "__all__"

特殊字段

特殊字段可以自己添加,和 Serializer 一样,一对多字段用 CharField,里面加上 source ,多对多用 SerializerMethodField ,特殊字段依然可以用 get_字段名 来返回该字段的值。

注意:存在定制字段,需要改写 create 方法。

class BookModelSerializers(serializers.ModelSerializer):
    # 默认将普通字段转化
    class Meta:
        model = Book
        fields = "__all__"

    # 特殊字段可以自己添加
    # 一对多用CharField,里面加上source
    publish = serializers.CharField(source="publish.name")
    publish = serializers.CharField(source="publish.pk")
    # 多对多用SerializerMethodField
    authors = serializers.SerializerMethodField()
    
    # 此时authors值取决于下面函数的返回值
    def get_authors(self, obj):
        authors_temp = []
        for authors_obj in obj.authors.all():
            authors_temp.append(authors_obj.name)
    
        return ",".join(authors_temp)

    # 存在定制字段,所以要改写create方法
    # def create(self, validated_data):
    #     print("validated_data", validated_data)
    #     book_obj = Book.objects.create(title=validated_data["title"], price=validated_data["price"], pub_date=validated_data["pub_date"], publish_id=validated_data["publish"]["pk"])
    #     book_obj.authors.add(*validated_data["authors"])
    #
    #     return book_obj

视图部分

需要用到 rest-framework 中的 APIView 类。

对每个数据表模型建立相应的视图类,并在视图类中通过不同的方法来接受前端以不同方法发来的数据。

from rest_framework.views import APIView
from .serializer import *


# Create your views here.
class BookViewSet(APIView):
    def get(self, request, *args, **kwargs):
        ...
    
    def post(self, request, *args, **kwargs):
        ...
        
    def put(self, request, *args, **kwargs):
        ...
        
    def patch(self, request, *args, **kwargs):
        ...

序列化方法一

使用 Django 中的 model_to_dict 。

book_list = Book.objects.all()
from django.forms.models import model_to_dict
import json
data = []
for obj in book_list:
    data.append(model_to_dict(obj))
return HttpResponse(json.dumps(data))

序列化方法二

使用 Serializer 将数据转成 json 数据。

data = serializers.serialize("json", book_list)
return HttpResponse(data)

序列化方法三

直接通过 Serializer 或者 ModelSerializer 来返回。

bs = BookSerializers(book_list, many=True)
bs = BookModelSerializers(book_list, many=True)

# 超链接时需要增加参数
bs = BookModelSerializers(book_list, many=True, context={'request': request})
return Response(bs.data)

提交 post 请求

与 Django 中的 ModelForm 类似,ModelSerializer 也有 is_valid 函数来判断验证是否通过, save 函数来讲数据保存到数据库中。

    def post(self, request, *args, **kwargs):
        bs = BookSerializers(data=request.data, many=False)
        request.data:post的数据
        bs = BookModelSerializers(data=request.data, many=False)

        # 超链接时需要增加参数
        bs = BookModelSerializers(data=request.data, many=False, context={'request': request})

        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

单条数据的请求

单条数据与之前的区别在于多传过来一个单条数据的 ID ,通过该 ID 值进行筛选工作。

class PublishViewSet(APIView):

    def get(self, request, *args, **kwargs):
        publish_list = Publish.objects.all()
        ps = PublishModelSerializers(publish_list, many=True)

        return Response(ps.data)

    def post(self, request):
        ps = PublishModelSerializers(data=request.data, many=False)

        if ps.is_valid():
            print(ps.validated_data)
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.error)

超链接 API

有时,想让该字段的输出值为超链接,这样也是可以实现的。需要将该字段设置为
HyperlinkedIdentityField 类型,其中 view_name 为在 urls.py 中设置的视图名, lookup_field 绑定数据表模型的 ID , lookup_url_kwarg 绑定为主键。

class BookModelSerializers(serializers.ModelSerializer):
    # 默认将普通字段转化
    class Meta:
        model = Book
        fields = "__all__"

    # 定制url
    publish = serializers.HyperlinkedIdentityField(
        view_name="detailpublish",
        lookup_field="publish_id",
        lookup_url_kwarg="pk"
    )

而包含超链接的字段进行实例化时,需要添加相应的参数:

bs = BookModelSerializers(book_list, many=True, context={'request': request})

urls 部分

对于视图类,只需要在 URL 中调用 as_view 函数即可。

注意:

  1. 整体数据和单条数据的操作不能用同一个视图类。
  2. 如果有超链接,需要给每个 URL 都加上 name 属性。
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^books/$', views.BookViewSet.as_view(), name="book"),
    url(r'^publishes/$', views.PublishViewSet.as_view(), name="publish"),
    url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="detailpublish"),
    url(r'^authors/$', views.AuthorViewSet.as_view(), name="author"),
    url(r'^books/(\d+)/$', views.BookDetailView.as_view(), name="detailbook"),
]

posted @ 2019-01-14 21:52  banshaohuan  阅读(197)  评论(0编辑  收藏  举报