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()), ] |
分类:
Restful
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架