Django - DRF - serializers 序列化组件

目录

一、Django内置的serializers模块 - 将对象序列化

1-1 单表操作(单表的get获取以及数据化)

二、DRF框架 - Serializer 组件

2-1 单表操作

2-1-1 缺少 safe=False 的错误信息 - 防止序列化的字典内套了列表

2-2 多表操作

2-2-1 models结构

2-2-2 View视图函数

2-2-3 serializers 自定义类 - 等待view视图函数对象的传入,以及对象处理的逻辑

三、DRF框架 - ModelSerializer组件

四、DRF - HyperlinkedIdentityField组件 - 用于链接的拼接

五、DRF - 反序列化

5-1 接收数据的校验 - is_valid()

5-2 数据的修改 -  instance=修改对象 + Ser类实例.save()

5-3 局部校验钩子 - validate_field_name -  用于单个字段的校验定义

5-3 全局校验钩子 - validate - 用于多个字段的组合校验


一、Django内置的serializers模块 - 将对象序列化

1-1 单表操作(单表的get获取以及数据化)

# 用django自带的序列化组件序列化
from django.core import serializers
import json

class Books(APIView):

    def get(self,request):

        response = {'status': 100, 'data': None}
        books = models.Book.objects.all()
        # 先构造出所有书籍的字典的列表,即将获取的所有书本对象进行json格式序列化操作
        ret=serializers.serialize('json',books)
        print(ret)
        # ret为json格式
        # [{"model": "app01.book", "pk": 1, "fields": {"name": "name", "price": "123"}}, {"model": "app01.book", "pk": 2, "fields": {"name": "\u6c34", "price": "15"}}, {"model": "app01.book", "pk": 3, "fields": {"name": "\u6c34\u90fd\u662f", "price": "15"}}]

        # 将json数据存入返回结构内,注意前台取出的data需要进行反序列化操作
        # 不建议将json格式放入字典内,建议将原始数据放入
        response['data'] = json.loads(ret)
        # 注意不能将字典(对象)格式使用HTTP直接返回前台
        return HttpResponse(response)

Django - DRF - serializers 序列化组件_第1张图片

 

二、DRF框架 - Serializer 组件

2-1 单表操作

from rest_framework.views import APIView
from rest_framework.serializers import Serializer
from rest_framework import serializers


# 写一个与modles内表类对应的Serializer类,用于获取需求序列化的字段
# 字段必须在modles对应表内进行定义
class BookSerializer(Serializer):
    name = serializers.CharField()
    # price=serializers.CharField()
    # date=serializers.CharField()


class Books(APIView):

    def get(self, request):

        # 序列化多个对象(many=True)
        books = models.Book.objects.all()
        # instance=books要序列化的queryset对象,many=True,表示序列化多条
        ser = BookSerializer(instance=books, many=True)
        print(ser.data)
        # [OrderedDict([('name', 'name')]), OrderedDict([('name', '水')]), OrderedDict([('name', '水都是')])]

        # instance:可以不写,按位置传 - instance位于位置传参的第一位
        # ser=BookSerializer(books,many=True)

        # 序列化单个对象 many=False
        book = models.Book.objects.all().first()
        ser=BookSerializer(book,many=False)

        # ser.data 拿到的是序列化之后的字典,字典里可能套了列表,所以safe=False
        return JsonResponse(ser.data, safe=False)

2-1-1 缺少 safe=False 的错误信息 - 防止序列化的字典内套了列表

 

2-2 多表操作

2-2-1 models结构

from django.db import models


# Create your models here.

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()

    publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)


class AuthorDatail(models.Model):
    nid = models.AutoField(primary_key=True)
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name

    def test(self):
        return self.email

2-2-2 View视图函数

from ap01 import models
from rest_framework.views import  APIView
from django.http import JsonResponse

from ap01.mySer import  BookSerializer

class Books(APIView):

    def get(self,request,*args,**kwargs):
        
        # 基于多个对象的序列化 many=True
        ret=models.Book.objects.all()
        book_ser=BookSerializer(ret,many=True)
        print(book_ser.data)
        return JsonResponse(book_ser.data,safe=False)

2-2-3 serializers 自定义类 - 等待view视图函数对象的传入,以及对象处理的逻辑

注意:

  • 使用source参数可指定字段名对应的字段内容
    • price = serializers.CharField() - 不使用source,则属性名字必须和字段一一对应
    • xx = serializers.CharField(source='name') - 使用source,xx属性对应传入对象的name字段
    • city = serializers.CharField(source='publish.city') - 使用source,city属性对应关系表publish表内的city字段
    • test = serializers.CharField(source='publish.test') - 使用source,test属性对应关系表publish表内的test方法
  • SerializerMethodField 必须结合自定义指定格式方法进行操作
  • 可以在 get_字段名 方法内继续使用serializers序列化操作
from rest_framework import serializers


class AuthorSerializer(serializers.Serializer):
    nid = serializers.CharField()
    name = serializers.CharField()
    age = serializers.CharField()


class BookSerializer(serializers.Serializer):
    # source的使用
    xx = serializers.CharField(source='name')
    price = serializers.CharField()
    city = serializers.CharField(source='publish.city')
    test = serializers.CharField(source='publish.test')
    publish_id = serializers.CharField()
 '''
    SerializerMethodField 对应指定方法获取返回值
    方法格式:get_字段名;必传参数:self,当前对象obj(book)

    publish=serializers.SerializerMethodField()
    def get_publish(self,obj):
        # obj 是当前book对象0
        dic={'name':obj.publish.name,'email':obj.publish.email}
        return dic
'''
    authors = serializers.SerializerMethodField()

    # def get_authors(self,book):
    #     #拿到这本书的所有作者
    #     aus=book.authors.all()
    #     # 拼出一个列表,列表中套字典,每个字典是一个作者
    #     ll=[]
    #     for a in aus:
    #         ll.append({'name':a.name,'age':a.age})
    #     return ll

    def get_authors(self, book):
        # 拿到这本书的所有作者
        aus = book.authors.all()
        # 可以继续用序列化类,来处理
        auth_ser = AuthorSerializer(aus, many=True)
        return auth_ser.data

Django - DRF - serializers 序列化组件_第2张图片

三、DRF框架 - ModelSerializer组件

总结:

  • ModelSerializer组件必须配合Meta使用,对指定的字段进行序列化处理和返回
  • Meta内注意事项:
    • model需导入models内对应处理表类
    • fields - 用于获取需处理的表内字段
      • fields='__all__' - 获取所有字段进行序列化处理;后续可用常规方式重写属性,覆盖all序列的操作
        Django - DRF - serializers 序列化组件_第3张图片
      • fields = ['nid','name'] - 获取指定字段进行序列化处理并返回
        Django - DRF - serializers 序列化组件_第4张图片
    • exclude=['publish','authors'] - 用于去除字段,不序列化并且不返回
      Django - DRF - serializers 序列化组件_第5张图片
    • depth = 2 - 关系表的深度指定(不建议使用,对数据库的频繁操作降低效率)
      Django - DRF - serializers 序列化组件_第6张图片
from ap01.models import Book
from rest_framework import serializers


class AuthorSerializer(serializers.Serializer):
    nid = serializers.CharField()
    name = serializers.CharField()
    age = serializers.CharField()

class BookSerializer(serializers.ModelSerializer):
    # 必须写一个Meta内部类
    class Meta:
        # 序列化的对象,models内的对应表类
        # 需导入from ap01.models import Book
        model = Book
        # 对表内所有字段进行序列化处理
        fields = '__all__'
        # 指定只取这两个字段
        # fields = ['nid','name']
        # 去掉指定的字段,选入字段不进行序列化且不返回
        # exclude=['publish','authors']
        # fields,跟exclude不能连用
        # 指定深度(官方建议小于10,我给你的建议小于3),和关联表的深度 - 不建议使用
        # depth = 2

    # 重写属性,覆盖Meta内初始化操作
    publish = serializers.CharField(source='publish.name')
    authors = serializers.SerializerMethodField()

    def get_authors(self, book):
        # 拿到这本书的所有作者
        aus = book.authors.all()
        # 可以继续用序列化类,来处理
        auth_ser = AuthorSerializer(aus, many=True)
        return auth_ser.data

四、DRF - HyperlinkedIdentityField组件 - 用于链接的拼接

'''
mySer.py
  HyperlinkedIdentityField 必传参数:
    - view_name:urls.py路由文件内反向解析名
    - lookup_field:models内对应路由传入的参数
    - lookup_url_kwarg:urls.py路由文件内对应有名参数名
        - 注意:可以传入跨表字段,必须是联系表
            例如:假设publish表类内存在外联关系表book - 'book_id'
'''
class PublishSerializer(serializers.Serializer):
    name = serializers.CharField()
    city = serializers.CharField()
    publish_url = serializers.HyperlinkedIdentityField(view_name='urls_publish',lookup_field='nid',lookup_url_kwarg='id')

'''
urls.py
'''
url(r'^publish/(?P\d+)', views.Publish.as_view(),name='urls_publish'),

'''
views.py
   PublishSerializer 必传参数:
    - instance:序列化对象
    - mangy:序列化对象的单复数
    - context:获取链接中的域名,即 http://127.0.0.1:8000
'''
class Publish(APIView):
    def get(self, request, *args, **kwargs):
        ret = models.Publish.objects.all()
        publish_ser = PublishSerializer(ret, many=True,context={'request': request})
        return JsonResponse(publish_ser.data, safe=False)

五、DRF - 反序列化

5-1 接收数据的校验 - is_valid()

注意:

  • 校验通过的数据自动存储:ser.save()
  • 校验未通过的数据形成错误报告:ser.errors
  • 校验规则以models内定义的为基础,可以再其基础上在mySer文件内进行规则设定(方式同Form组件)
    Django - DRF - serializers 序列化组件_第7张图片Django - DRF - serializers 序列化组件_第8张图片
'''
mySer.py
    获取序列化数据、设置校验规则
'''

class PublishSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Publish
        fields = '__all__'

    # 自定义校验规则
    # name = serializers.CharField(min_length=2, error_messages={'required': '必填字段'})
    # city = serializers.CharField(required=False)

'''
view.py视图
    接收数据(JSON格式)进行校验 - 校验通过使用save将反序列化数据存入数据库
    若存在校验错误 - 存储在errors内
'''
class Publish(APIView):

    def post(self, request, *args, **kwargs):
        response = {'status': 100, 'msg': '成功'}
        ser = PublishSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
        else:
            response['status'] = 101
            response['msg'] = ser.errors
        return JsonResponse(response, safe=False)

Django - DRF - serializers 序列化组件_第9张图片

Django - DRF - serializers 序列化组件_第10张图片

5-2 数据的修改 -  instance=修改对象 + Ser类实例.save()

'''
urls.py
'''
from django.conf.urls import url
from django.contrib import admin
from ap01 import views
urlpatterns = [
    # 由于publish两种路由,所以前者无参路由必须使用结束符
    url(r'^publish/$', views.Publish.as_view()),
    url(r'^publish/(?P\d+)', views.Publish.as_view(),name='urls_publish'),
]


'''
mySer.py - 校验规则
'''
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = '__all__'

    name = serializers.CharField(min_length=2, error_messages={'required': '必填字段'})
    email = serializers.CharField(required=False)


'''
views.py - put数据提交修改数据库内容
'''
class Publish(APIView):

    def put(self, request, id, *args, **kwargs):
        response = {'status': 100, 'msg': '成功'}
        # 获取修改数据的单个对象 + 提交的数据
        ret = models.Publish.objects.all().filter(pk=id).first()
        ser = PublishSerializer(data=request.data, instance=ret)
        if ser.is_valid():
            ser.save()
        else:
            response['status'] = 101
            response['msg'] = ser.errors
        return JsonResponse(response, safe=False)

Django - DRF - serializers 序列化组件_第11张图片

5-3 局部校验钩子 - validate_field_name -  用于单个字段的校验定义

'''
局部校验钩子:validate_字段名
校验不通过 - 抛出指定ValidationError异常
    (from rest_framework.exceptions import ValidationError)
校验通过 - 返回校验通过的对象值

'''
from rest_framework.exceptions import ValidationError

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = '__all__'

    name = serializers.CharField(min_length=2, error_messages={'required': '必填字段'})
    email = serializers.CharField(required=False)

    def validate_name(self, value):
        pub = models.Publish.objects.all().filter(name=value).first()
        if pub:
            raise ValidationError('同名对象已存在!')
        else:
            return value

Django - DRF - serializers 序列化组件_第12张图片

5-3 全局校验钩子 - validate - 用于多个字段的组合校验

'''
全局校验钩子:validate
若校验不通过:抛出错误ValidationError
若校验通过:返回校验通过的对象
'''

from rest_framework.exceptions import ValidationError


class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = '__all__'

    name = serializers.CharField(min_length=2, error_messages={'required': '必填字段'})
    email = serializers.CharField(required=False)

    def validate_name(self, value):
        pub = models.Publish.objects.all().filter(name=value).first()
        if pub:
            raise ValidationError('同名对象已存在!')
        else:
            return value

    def validate(self, attrs):
        # attrs 是所有校验通过数据的字典
        name = attrs.get('name')
        city = attrs.get('city')
        if name == city:
            raise ValidationError('出版社名不可与城市名相同!')
        else:
            return attrs

Django - DRF - serializers 序列化组件_第13张图片

 

你可能感兴趣的:(Django,DRF)