restful——序列化组件
一 、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:
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
views:
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 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 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指定执行
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')
choices的用法: 详情
三 rest-framework序列化之ModelSerializer
官方: 网关链接
models 中:
import datetime from django.db import models
class ExecuteUser(models.Model): uid = models.AutoField(primary_key=True) name = models.CharField(max_length=64, null=True, blank=True) class TestInfo(models.Model): """ 测试记录详情 """ uid = models.AutoField(primary_key=True) request_id = models.CharField(max_length=64, null=True, blank=True)# 关系 sub_index = models.ForeignKey(to='self', to_field='uid', on_delete=models.SET_NULL, blank=True, null=True,# 执行人 execute_user = models.ForeignKey(to="ExecuteUser", to_field='uid', on_delete=models.SET_NULL, blank=True, null=True, related_name="execute_user", db_column='execute_user')
views 中:
class GetTestData(GenericAPIView): def get(self, request): params = request.query_params # 获取所有数据 _data = TestInfo.objects.all() resp_info = my_serializer.TestInfoSerializers(instance=_data, many=True) resp = [] for i in resp_info.data: _dict = dict(i) resp.append(_dict) return JsonResponse(resp, safe=False)
my_serializers中:
设置queryset后, read_only=True可以不设置, 就默认读写权限
# -*- coding: utf-8 -*- from rest_framework import serializers from . import models class TestInfoSerializers(serializers.ModelSerializer): """ cbt任务测试序列化组件 """ execute_user = serializers.SlugRelatedField(slug_field='name', queryset=models.ExecuteUser.objects.all()) class Meta: model = models.TestInfo # 所有字段 fields = "__all__" # depth = 1 # 显示外键关联层 def create(self, validated_data): # 指定 SlugRelatedField 后必须重写 create test_info = models.TestInfo.objects.create(**validated_data) return test_info class ExecuteUserSerializers(serializers.ModelSerializer): """ 执行用户表序列化组件 """ class Meta: model = models.ExecuteUser fields = "__all__"
四 生成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') 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'),
五 序列化组件之请求数据校验和保存功能
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方法
通过源码查看留的校验字段的钩子函数:
#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('心急啊')
序列化组件源码分析
序列化组件,先调用__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接口:
视图层:
from app01.My_Serialize import My_ser from app01 import models from rest_framework.response import Response from rest_framework.views import APIView class Book(APIView): def get(self,request): response = {"status":"100","msg":"成功"} book_list = models.Book.objects.all() book_ser = My_ser(book_list,many=True) response["book_list"] = book_ser.data return Response(response) def post(self,request): response = {"status":"100","msg":"成功"} # print(request.data) book_ser = My_ser(data=request.data) if book_ser.is_valid(): book_ser.save() response['book'] = book_ser.data else: response['msg'] = book_ser.errors return Response(response) class Books(APIView): def get(self,request,id): # response = {"status":"100","msg":"成功"} book_list = models.Book.objects.filter(pk=id).first() book_ser = My_ser(book_list,many=False) # response["book"] = book_ser.data return Response(book_ser.data) def put(self,request,id): book = models.Book.objects.filter(pk=id).first() obj = My_ser(data=request.data,instance=book) if obj.is_valid(): obj.save() return Response(obj.data) else: return Response(obj.errors) def delete(self,request,id): models.Book.objects.filter(pk=id).delete() return Response("删除成功")
url:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^book/', views.Book.as_view()), url(r'^books/(?P<id>\d+)', views.Books.as_view()), ]