Restful framework【第三篇】序列化组件

 


基本使用#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
-序列化
    -对象,转成json格式
用drf的序列化组件
  -定义一个类继承class BookSerializer(serializers.Serializer):
  -写字段,如果不指定source,字段名必须跟数据库字段名对应(source指定的值跟字段名不能重复)
  -source还可以指定方法
  -publish=serializers.SerializerMethodField()
    def get_publish(self,obj):
        obj.publish
        #obj.authors.all()
                 
-Serializer
-ModelSerializer
    class Meta:
        # 指定表模型
        model = models.Book
        # 序列化所有字段
        fields = '__all__'
        # 只想序列化title和id这俩字段
        # fields = ['title', 'id']
        # exclude 和fields 不要连用
        # exclude = ['title']
        depth=1
         
          -反序列化:
            -保存
              ser=BookSer(data=传过来的字典)
              if ser.is_valid()
                ser.save()
            -取校验通过的数据:
              ser.data
            -修改
              ser=BookSer(data=传过来的字典,instance=要修改的对象)
              if ser.is_valid()
                ser.save()
              else:
                errors=ser.errors
 
          # 如果想让publish字段显示出版社的名字
            # publish = serializers.CharField(source='publish.name')
            # authors = serializers.SerializerMethodField()
            # def get_authors(self, obj):
            #     author_list = obj.authors.all()
            #     author_ser = AuthorSer(instance=author_list, many=True)
            #     return author_ser.data

Django自带序列化组件#

serializers(把对象序列化成json字符串)#

from django.core import serializers

 

from django.core import serializers
def test(request):
    book_list = Book.objects.all()    
    ret = serializers.serialize("json", book_list)
    return HttpResponse(ret)

rest-framework序列化之Serializer#

models部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

view部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers
 
 
from rest_framework import serializers
<br><...   这一块代码最好新建一个 .py文件放在里面,这样的话看起来就不是那么乱了
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
...><br>
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
        return Response(bs.data)
     # 序列化方式4:
      # ret=models.Book.objects.all().values('nid','title')
     # dd=list(ret)
        # return HttpResponse(json.dumps(dd))

注意:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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')

小结#

1
2
3
4
5
6
7
8
9
10
11
12
# 1 变量名和source指定的值不能一样
# 2 source='publish.name'还支持继续 .
# 3 source 还支持方法(没用)
# 4 支持写方法,如下
    #方法一定传一个参数,是当前book对象
    publish_dic=serializers.SerializerMethodField()
    def get_publish_dic(self,obj):
    # 猜,这个obj应该是谁,当前book对象
      return {'id':obj.publish.pk,'name':obj.publish.name}
             
在线格式化json
-https://www.json.cn/

rest-framework序列化之ModelSerializer#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        # fields = "__all__"
        fields=['nid','title','authors','publish']
        # exclude=('nid',)   #不能跟fields同时用
        # depth = 1    #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
    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(极少数)#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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')
    authors=serializers.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'),

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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()  # 生成记录
            return Response(bs.data)
        else:
 
            return Response(bs.errors)

 

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

#这种方式要保存,必须重写create方法

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

1
2
3
4
5
6
7
8
9
10
11
12
13
#is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)
def validate_title(self, value):
        from rest_framework import exceptions
        raise exceptions.ValidationError('看你不顺眼')
        return value
 
#全局
def validate(self, attrs):
    from rest_framework import exceptions
    if attrs.get('title')== attrs.get('title2'):
        return attrs
    else:
        raise exceptions.ValidationError('不想等啊')

序列化组件源码分析#

1
2
3
4
5
序列化组件,先调用__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
当参数传过去,判断是方法就加括号执行,是属性就把值取出来

图书的增删查改resful接口与上面知识点的实例#

视图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
# Create your views here.
from django.views import View
 
 
class Test(View):
    def dispatch(self, request, *args, **kwargs):
        # 写代码
        obj = super().dispatch(request, *args, **kwargs)
        # 写代码
        return obj
 
    def get(self, request, *args, **kwargs):
        return HttpResponse('cbv_get')
 
    def post(self, request, *args, **kwargs):
        return HttpResponse('cbv_post')
 
 
user_list = [{'id': 1, 'name': 'lqz', 'age': 18}, {'id': 2, 'name': 'egon', 'age': 17},
             {'id': 3, 'name': 'xiaohou', 'age': 16}]
 
 
def users(request):
    response = {'status': 100, 'errors': None}
    if request.method == 'GET':
        response['users'] = user_list
        return JsonResponse(response, safe=False)
    if request.method == 'POST':
        name = request.POST.get('name')
        age = request.POST.get('age')
        user_list.append({'id': len(user_list) + 1, 'name': name, 'age': age})
        # response['user'] = {'id':len(user_list),'name': name, 'age': age}
        response['msg'] = '新增成功'
        return JsonResponse(response)
 
 
def user(request, id):
    response = {'status': 100, 'errors': None}
    if request.method == 'GET':
        id = int(id)
        response['user'] = user_list[id]
        return JsonResponse(response)
 
 
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
 
 
# 基于drf写接口,写cbv
class DrfTest(APIView):
 
    def get(self, request, *args, **kwargs):
        # request是封装之后的request了,原来的request是request._request
        print(type(request._request))
        print(type(request))
        # 问:当前request对象并没有这些属性,但是能打印出来,为什么?
        # 修改了getattr
        print(request.method)
        print(request.POST)
        print(request.GET)
        # 就相当于:
        print(request.query_params)
        print(request._request.GET)
        response = {'status': 100, 'errors': None}
        response['users'] = user_list
        # 用drf的Response,可以通过请求客户端来判断返回数据格式是什么样的
        return Response(response)
        # return JsonResponse(response)
 
    def post(self, request, *args, **kwargs):
        # post 提交的数据,urlencode,formdate,json格式,都能从data中取出来
        name = request.data.get('name')
        # request.FILES
        print(name)
        return HttpResponse('ok')
 
 
from app01 import models
from app01.MySer import BookSerializer
 
class Auth():
    def authenticate(self,request):
        pass
 
 
# 写一个获取所有图书的接口
class Books(APIView):
    authentication_classes=[Auth,]
    def get(self, request, *args, **kwargs):
 
        response = {'status': 100, 'msg': '成功'}
        book_list = models.Book.objects.all()
        # 第一个参数是要序列化的queryset对象,如果序列化多条,必须指定many=True
        # 问?什么情况下many=False,instance=单个对象的时候
        book_ser = BookSerializer(book_list, many=True)
        print(book_ser.data)
        response['books'] = book_ser.data
        return Response(response)
 
    def post(self, request):
        response = {'status': 100, 'msg': '成功'}
        # 提交的字典
        # book = request.data
        # 传统方法,创建对象保存
        # 新方法,通过序列化组件保存,必须用继承自ModelSerializer
        # data注意是data
        book_ser = BookSerializer(data=request.data)
        # is_valid提交的字段校验通过
        if book_ser.is_valid():
            book_ser.save()
            response['book'] = book_ser.data
        else:
            response['msg'] = book_ser.errors
        # return Response(book_ser.data)
        return Response(response)
 
 
class Book(APIView):
 
    def get(self, request, id):
        response = {'status': 100, 'msg': '成功'}
        book = models.Book.objects.filter(pk=id).first()
        book_ser = BookSerializer(book, many=False)
        response['book'] = book_ser.data
        return Response(response)
 
    def put(self, request, id):
        response = {'status': 100, 'msg': '成功'}
        book = models.Book.objects.filter(pk=id).first()
        # 修改的话,要把book对象传过来
        book_ser = BookSerializer(data=request.data, instance=book)
        # is_valid提交的字段校验通过
        if book_ser.is_valid():
            # save既可以修改,又可以更新
            book_ser.save()
            response['book'] = book_ser.data
        else:
            response['msg'] = book_ser.errors
        # return Response(book_ser.data)
        return Response(response)
 
    def delete(self,request,id):
        response = {'status': 100, 'msg': '删除成功'}
        book = models.Book.objects.filter(pk=id).delete()
        return Response(response)

模板层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from django.db import models
 
# Create your models here.
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 test(self):
        return self.title + str(self.price)
 
    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
    # return str(self.pk)
 
 
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    #
    # def __str__(self):
    #     return self.name

自己手动创建的序列化组件层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from rest_framework import serializers
 
 
# from rest_framework.request import Request
 
class AuthorSer(serializers.Serializer):
    id = serializers.CharField()
    name = serializers.CharField()
    age = serializers.CharField()
 
 
# class BookSerializer(serializers.Serializer):
#     id = serializers.CharField()
#     # 通过source可以改名
#     name = serializers.CharField(source='title')
#     price = serializers.CharField()
#
#     xxx = serializers.CharField(source='test')
#     # 1 变量名和source指定的值不能一样
#     # 2 source='publish.name'还支持继续 .
#     # 3 source 还支持方法(没用)
#     # publish_name = serializers.CharField(source='publish.name')
#     # publish_id = serializers.CharField(source='publish.pk')
#     # 4 支持写方法,如下
#         #方法一定传一个参数,是当前book对象
#     publish_dic=serializers.SerializerMethodField()
#     def get_publish_dic(self,obj):
#         # 猜,这个obj应该是谁,当前book对象
#         return {'id':obj.publish.pk,'name':obj.publish.name}
#     authors=serializers.SerializerMethodField()
#     # def get_authors(self,obj):
#     #     # 所有作者queryset对象
#     #     author_list=obj.authors.all()
#     #     ll=[ {'name':author.name,'id':author.pk} for author in author_list]
#     #     return ll
#     def get_authors(self,obj):
#         # 所有作者queryset对象
#         author_list=obj.authors.all()
#         author_ser=AuthorSer(instance=author_list,many=True)
#         return author_ser.data
# ModelSerializer跟表模型绑定的序列化
from app01 import models
 
 
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定表模型
        model = models.Book
        # 序列化所有字段
        fields = '__all__'
        # 只想序列化title和id这俩字段
        # fields = ['title', 'id']
        # exclude 和fields 不要连用
        # exclude = ['title']
        # 深度,表示连表的深度
        # 不建议使用:下几层要取得参数不能控制,官方建议不要超过10,我给你的建议不要超过3
        # depth=1
        # 全取出来之后,可以在后面覆盖之前的值
        # 如果想让publish字段显示出版社的名字
        # publish = serializers.CharField(source='publish.name')
        # authors = serializers.SerializerMethodField()
        # def get_authors(self, obj):
        #     author_list = obj.authors.all()
        #     author_ser = AuthorSer(instance=author_list, many=True)
        #     return author_ser.data
 
    title = serializers.CharField(max_length=6, min_length=3, error_messages={'max_length': '太长了'})
 
    # 也有局部钩子和全局钩子
    def validate_title(self, value):
        from rest_framework import exceptions
        print(value)
        if value.startswith('sb'):
            raise exceptions.ValidationError('不能以sb开头')
        return value
    # def validate_title(self, value):
    #     from rest_framework import exceptions
    #     raise exceptions.ValidationError('看你不顺眼')
    #     return value

路由

1
2
3
4
5
6
7
8
9
10
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', views.DrfTest.as_view()),
    # 在这写的实际上就是as_view()内view的内存地址
    url(r'^books/', views.Books.as_view()),
    url(r'^book/(?P<id>\d+)', views.Book.as_view()),
]

  

posted @   鲸鱼的海老大  阅读(211)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示
CONTENTS