rest-framework之序列化组件

一 rest-framework序列化之Serializer

 models部分:

from django.db import models

# Create your models here.


class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()  #int类型
    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
#创建三种类,其中书和出版社时多对一的关系,外键放在多一方。书和作者是多对多的关系,建第三张表

 views部分:

from rest_framework.views import APIView #在View上封装的
from rest_framework.response import Response #用来响应,Json序列化
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers #django自带的序列化文件


from rest_framework import serializers #rest封装的序列化模块

class BookSerializers(serializers.Serializer):
    title=serializers.CharField(max_length=32)
    price=serializers.IntegerField()
    pub_date=serializers.DateField()
    publish=serializers.CharField(source="publish.name")  #可以直接点属性
    #authors=serializers.CharField(source="authors.all")  #可以直接点方法,但是不加括号
    authors=serializers.SerializerMethodField()
    def get_authors(self,obj):
        temp=[]
        for author in obj.authors.all():
            temp.append(author.name)
        return temp
  #此处可以继续用author的Serializers,
  # def get_authors(self,obj):
    #     ret=obj.authors.all()
    #     ss=AuthorSerializer(ret,many=True)
    #     return ss.data

class BookViewSet(APIView):

    def get(self,request,*args,**kwargs):
        book_list=Book.objects.all()
        # 序列化方式1:
        # from django.forms.models import model_to_dict
        # import json
        # data=[]
        # for obj in book_list:
        #     data.append(model_to_dict(obj)) #直接将对象变成字典
        # print(data)
        # return HttpResponse("ok")

        # 序列化方式2:
        # data=serializers.serialize("json",book_list)
        # return HttpResponse(data)

        # 序列化方式3:
        bs=BookSerializers(book_list,many=True)     #many=True代表有多条数据,如果只有一条数据,many=False,默认就是false
        return Response(bs.data)
     # 序列化方式4: 
      # ret=models.Book.objects.all().values('nid','title')
     # dd=list(ret)
        # return HttpResponse(json.dumps(dd))

注意:

1. 浏览器中访问时,必须在settings中配置app,将rest_framework加入其中,这样放回Reponse时不会出错

2. source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))

如在模型中定义一个方法,直接可以在在source指定执行

class UserInfo(models.Model):
    user_type_choices = (
        (1,'普通用户'),
        (2,'VIP'),
        (3,'SVIP'),
    )
    user_type = models.IntegerField(choices=user_type_choices)

    username = models.CharField(max_length=32,unique=True)
    password = models.CharField(max_length=64)


#视图
ret=models.UserInfo.objects.filter(pk=1).first()
aa=ret.get_user_type_display()

#serializer
xx=serializers.CharField(source='get_user_type_display')

二 rest-framework序列化之ModelSerializer

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book     #指定model类,这里的
        # fields = "__all__"    #所有的字段
        fields=['nid','title','authors','publish']
        # exclude=('nid',)   #不能跟fields同时用
        # depth = 1    #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层 ,1就拿出外键的第一层详细数据
    publish=serializers.SerializerMethodField() #可以重写属性这个方法可以与下面的函数名对应
    def get_publish(self,obj):
        return obj.publish.name
    authors=serializers.SerializerMethodField()
    def get_authors(self,obj):
        ret=obj.authors.all()
        ss=AuthorSerializer(ret,many=True)
        return ss.data     #返回的值就是返回给前端的值

三 生成hypermedialink(极少数)

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = "__all__"
    # 生成连接,直接查看出版社详情
    publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id', lookup_url_kwarg='pkk')
    #第一值为url中的别名,第二个值为当前对象的publish的值,第三个为有名分组名。
    authors=serializers.SerializerMethodField()
    #只有这种SerializerMethodField方法可以这样自定义返回的值
    def get_authors(self,obj):
        ret=obj.authors.all()
        ss=AuthorSerializer(ret,many=True)
        return ss.data
#--------------

res=BookSerializers(ret,many=True,context={'request': request}) #固定写法

#--------------

class Publish(APIView):
    def get(self,request,pkk):  #获取有名分组名数据
        print(pkk)
        return HttpResponse('ok')
#----路由---
url(r'^publish/(?P<pkk>\d+)$', views.Publish.as_view(),name='ttt'),

 四 序列化组件之请求数据校验和保存功能

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model=Book
        fields="__all__"

class BookView(APIView):

    def post(self, request):

        # 添加一条数据
        print(request.data)

        bs=BookSerializers(data=request.data) #通过序列化文件来校验字段
        if bs.is_valid():
            bs.save()  # 生成记录  ModelSerializer只有这个类有save方法
            return Response(bs.data) #返回添加的信息
        else:

            return Response(bs.errors)#返回错误信息

自定义errors的值:

#注意自定义create方法的使用

class BookSerializer1(serializers.Serializer):
    title=serializers.CharField(error_messages={'required': '标题不能为空'})

#这种方式要保存,还有继承serializers.ModelSerializer类中自定义的属性,都必须重写create方法

    def create(self, validated_data):
        authors=validated_data.pop('authors') #拿出字段值,并删除字典中的key:value值
        obj=models.Book.objects.create(**validated_data)  #创建book对象
        obj.author.add(*authors) #第三张表中添加数据
        return obj

  

通过源码查看留的校验字段的钩子函数:

#源码的查找顺序
#is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)


局部
def validate_title(self, value): #value是字段的值
        from rest_framework import exceptions
        raise exceptions.ValidationError('看你不顺眼')  #如果校验不通过就报错
        return value

#全局 
def validate(self, attrs): #attr是一个字典
    from rest_framework import exceptions
    if attrs.get('title')== attrs.get('title2'):
        return attrs
    else:
        raise exceptions.ValidationError('不想等啊')

五 序列化组件源码分析

序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
当参数传过去,判断是方法就加括号执行,是属性就把值取出来

猜你喜欢

转载自blog.csdn.net/qq_35540539/article/details/83064670