02 DRF之ModelSerializer

编辑本文章

一、Django序列化方法

Django序列化方法一,使用Values和JsonResponse来实现

弊端:需要自己处理外键

    def get(self,request):
        book_list=Book.objects.values("id","title","pub_time","publisher")
        # queryset无法直接被json系列化,先对其list
        book_list=list(book_list)
        ret=[]
        for book in book_list:
            publisher_id=book["publisher"]
            publisher_obj=Publisher.objects.filter(id=publisher_id).first()
            book["publisher"]={"id":publisher_id,"title":publisher_obj.title}
            ret.append(book)
        # ensure_ascii=False避免中文乱码
        # ret=json.dumps(book_list,ensure_ascii=False)
        # return HttpResponse(ret)
        return JsonResponse(ret,safe=False,json_dumps_params={"ensure_ascii":False})
View Code

 

Django serializers实现序列化

弊端:外键任然以主键的方式存在,且有其他前端无用的字段

    def get(self,request):
        book_list=Book.objects.all()
        ret=serializers.serialize("json",book_list,ensure_ascii=False)
        return HttpResponse(ret)
View Code

二、组件djangorestframework序列化

1、安装djangoresuframework

2、在APP中注册rest_framework应用

3、创建自己的serializers模块,在模块中创建model对应的Serializer类

from rest_framework import serializers
class BookSerializer(serializers.Serializer):
    id=serializers.IntegerField()
    title=serializers.CharField(max_length=64)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category=serializers.ChoiceField(choices=CHOICES,source="get_category_display")
    pub_time=serializers.DateField()
View Code

4、在视图模块中导入模块对应的Serializer类,从rest_framework.views中导入APIView,从rest_framework.response中导入Response

5、创建视图类,继承APIView,返回Response类,被序列化的数据在对应类Serializer().data中

from rest_framework.views import APIView
from rest_framework.response import Response
from DRFServer.serializers import BookSerializer

class BookView(APIView):
    def get(self,request):
        # book_obj=Book.objects.first()
        # 一条数据
        # ret=BookSerializer(book_obj)
        book_list=Book.objects.all()
        # 多条数据
        ret=BookSerializer(book_list,many=True)
        return Response(ret.data)
View Code

  6、外键采用嵌套类得方式,ManyToMany字段添加many=True参数

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=64)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category=serializers.ChoiceField(choices=CHOICES,source="get_category_display")
    pub_time=serializers.DateField()
    
    publisher=PublisherSerializer()
    # many=True表示ManyToMany
    author=AuthorSerializer(many=True)
View Code

7、Choice字段,需添加source属性,字段为category,source属性值为get_category_display,字段为go,source属性值为get_go_display

三、DRF反序列化

对前端上传得数据进行反序列化。

1、对Serializer字段进行修改,添加相关属性

required=False:id字段无需上传,也就无需验证,添加required属性

read_only=True:该字段只在序列化时使用,反序列化忽略

write_only=True:该字段只在反序列化时使用,序列化时忽略。字段名称需要和前端沟通,需一一对应。

2、在对应Serializer类中添加create方法,对验证过来的数据通过ORM进行保存,注意字段名称

class BookSerializer(serializers.Serializer):
    id=serializers.IntegerField(required=False)#required=False标示不验证
    title=serializers.CharField(max_length=64)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    #read_only=True只在序列化的时候使用,
    category=serializers.ChoiceField(choices=CHOICES,source="get_category_display",
                                     read_only=True)
    # w_category和前端沟通好的字段,前端上传w_category,且write_onle=True,标示是反序列化字段
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time=serializers.DateField()
    #只在序列化时使用
    publisher=PublisherSerializer(read_only=True)
    #前端回传publisher_id字段,只反序列化使用
    publisher_id=serializers.IntegerField(write_only=True)
    # many=True表示ManyToMany,只在序列化时使用
    author=AuthorSerializer(many=True,read_only=True)
    #author_list字段用于前端上传作者id,只反序列化使用
    author_list=serializers.ListField(write_only=True)
    def create(self, validated_data):
        book=Book.objects.create(title=validated_data['title'],
                            category=validated_data['w_category'],
                            pub_time=validated_data['pub_time'],
                            publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data['author_list'])
        return book
View Code

3、在View视图中添加post方法,用户数据存储在request.data中

4、实例化对应的Serializer,并传入data

5、对数据进行验证,使用serializer.is_valid(),验证通过进行数据保存并返回用户提交的数据,验证失败返回Response(serializer.errors)

class BookView(APIView):
    def get(self,request):
        pass
    def post(self,request):
        serializer=BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)
View Code

四、DRF的PUT请求验证部分字段

用户针对某个资源发送put请求,以更新资源

1、在url中添加路由,注意参数id

2、创建对应的视图类,定义put方法

from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from django.core import serializers
from DRFServer.models import Book,Publisher
import json
# Create your views here.
from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response
from DRFServer.serializers import BookSerializer
# class BookView(View):
    # 版本一,使用values和JsonResponse实现序列号
    # def get(self,request):
    #     book_list=Book.objects.values("id","title","pub_time","publisher","author")
    #     # queryset无法直接被json系列化,先对其list
    #     book_list=list(book_list)
    #     ret=[]
    #     for book in book_list:
    #         publisher_id=book["publisher"]
    #         publisher_obj=Publisher.objects.filter(id=publisher_id).first()
    #         book["publisher"]={"id":publisher_id,"title":publisher_obj.title}
    #         ret.append(book)
    #     # ensure_ascii=False避免中文乱码
    #     # ret=json.dumps(book_list,ensure_ascii=False)
    #     # return HttpResponse(ret)
    #     return JsonResponse(ret,safe=False,json_dumps_params={"ensure_ascii":False})
    # 版本二,使用django serializers实现序列号
    # def get(self,request):
    #     book_list=Book.objects.all()
    #     ret=serializers.serialize("json",book_list,ensure_ascii=False)
    #     return HttpResponse(ret)
class BookView(APIView):
    def get(self,request):
        # book_obj=Book.objects.first()
        # 一条数据
        # ret=BookSerializer(book_obj)
        book_list=Book.objects.all()
        # 多条数据
        ret=BookSerializer(book_list,many=True)
        return Response(ret.data)
    def post(self,request):
        serializer=BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)
class BookEditView(APIView):
    def get(self,request,id):
        book_obj=Book.objects.filter(id=id).first()
        ret=BookSerializer(book_obj)
        return Response(ret.data)
    def put(self,request,id):
        data=request.data
        book_obj = Book.objects.filter(id=id).first()
        # partial=True允许部分更新
        serializers=BookSerializer(instance=book_obj,data=data,partial=True)
        if serializers.is_valid():
            # 方式一
            # serializers.update(book_obj,serializers.validated_data)
            #方式二
            serializers.save()
            return Response(serializers.validated_data)
        else:
            return Response(serializers.errors)
View Code

a、拿到资源的query对象

b、创建serializers实例,传入instance(query对象),data(用户put的数据),partial(True标示允许部分更新)参数,并对数据进行验证

c、验证过后调用实例的save方法,或者调用update方法,注意,update方法需要传入对象实例和验证后的数据

d、验证失败返回Response(serializers.errors)

3、在定义的Serializer类中添加update方法,接收instance和validated_data,并通过ORM方法对数据进行更新,更新完成调用save方法,并返回实例

# _*_ coding:utf-8 _*_
# Author:huangmingya
# DateTime: 2019/6/24 11:03

from rest_framework import serializers
from DRFServer.models import *

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(required=False)#required=False标示不验证
    title=serializers.CharField(max_length=64)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    #read_only=True只在序列化的时候使用,
    category=serializers.ChoiceField(choices=CHOICES,source="get_category_display",
                                     read_only=True)
    # w_category和前端沟通好的字段,前端上传w_category,且write_onle=True,标示是反序列化字段
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time=serializers.DateField()
    #只在序列化时使用
    publisher=PublisherSerializer(read_only=True)
    #前端回传publisher_id字段,只反序列化使用
    publisher_id=serializers.IntegerField(write_only=True)
    # many=True表示ManyToMany,只在序列化时使用
    author=AuthorSerializer(many=True,read_only=True)
    #author_list字段用于前端上传作者id,只反序列化使用
    author_list=serializers.ListField(write_only=True)
    def create(self, validated_data):
        book=Book.objects.create(title=validated_data['title'],
                            category=validated_data['w_category'],
                            pub_time=validated_data['pub_time'],
                            publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data['author_list'])
        return book
    def update(self, instance, validated_data):
        instance.title=validated_data.get("title",instance.title)
        instance.category=validated_data.get("w_category",instance.category)
        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("author_list"):
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance
View Code

 

5、DRF数据类容验证

自定义验证字段,优先于钩子函数验证

1、验证器内部使用局部钩子函数验证指定字段,使用validate_字段名方法验证指定字段

2、全局钩子验证字段,使用validate方法

3、自定义验证方法,可以作用于多个字段

  在字段中添加validators属性,接收一个列表,列表中是方法名

 

posted @ 2019-06-22 14:12  丫丫625202  阅读(204)  评论(0编辑  收藏  举报