序列化方式常见的有以下几种:
- model_to_dict
model_to_dict是Django ORM下的语句,可以把model对象转换成一个字典
from django.forms.models import model_to_dict
from app01.models import Publish
obj = Publish.objects.filter(pk=1).first()
obj
<Publish: 人民出版社>
model_to_dict(obj)
{'id': 1, 'name': '人民出版社', 'email': '123@qq.com'}
- list强转
#QuerySet无法直接序列化,需要转换成list
publish_list = list(Publish.objects.all().values("name", "email"))
print(publish_list)
[{'name': '人民出版社', 'email': '123@qq.com'}, {'name': '清华出版社', 'email': '345@qq.com'}]
- Django原生的serializers
publish_list = Publish.objects.filter(pk=1)
from django.core import serializers
#serialize(format, queryset, **options)
ret = serializers.serialize("json", publish_list)
print(ret)
[{"model": "app01.publish",
"pk": 1,
"fields": {
"name": "\u82f9\u679c\u51fa\u7248\u793e",
"email": "123@qq.com"
}
}
]
- restframework 这里利用restframework封装出来的serializers,其用法与Django的Form组件很相似 可以序列化QuerySet和model对象
from rest_framework.views import APIView
from rest_framework import serializers
#创建一个序列化类
class PublishSerializers(serializers.Serializer):
name = serializers.CharField()
email = serializers.CharField()
class PublishView(APIView):
def get(self, request):
publish_list = Publish.objects.filter(pk=1)
ret = PublishSerializers(publish_list, many=True)
#可以序列化QuerySet和model对象,many=True代表转换的是QuerySet,默认为False
print(ret.data)
#结果ret
#[OrderedDict([('name', '人民出版社'), ('email', '123@qq.com')])]
#得出一个OrderedDict对象,这个对象本质就是有序字典
return HttpResponse("ok")
def post(self, request):
pass
原生request与restframework的request
原生request
使用postman发送x-www-form-urlencoded数据后看一下request.body和request.POST都收到了什么
def post(self, request):
print("POST==>", request.POST)
print("body==>", request.body)
return HttpResponse("POST ok")
结果:
POST==> <QueryDict: {'a': ['1'], 'b': ['2']}> #处理过的数据
body==> b'a=1&b=2' #请求体中的数据,没有处理过的原始数据
由上可知,request.POST拿到一个字典,其过程就是判断contentType如果等于urlencoded,那么就将接收到的数据转换为一个字典,如果是其它类型例如JSON那么request.POST就是个空字典 也就是说原生Django的request只支持form表单数据的解析 如果传过来的是JSON数据,那么就只能从request.body中拿到字符串,然后再反序列化成字典
request.POST:
if contentType:urlencoded:
a=1&b=2----->{"a":1,"b":2}
restframework的request
APIViwe还是继承原生Django的View,但自己构建了一个dispatch(restframework的关键点都在这里,CBV(class base views)会用到) 在这个dispatch中构建了一个新的request
class PublishView(APIView):
def post(self, request):
#新的request支持的操作
print("request.data==>", request.data)
print("request.data_type==>", type(request.data))
#前端发送JSON数据,接收到的是一个字典,说明接收的同时完成了反序列化
#request.data==> {'a': 1, 'b': 2}
#request.data_type==> <class 'dict'>
return HttpResponse("POST ok")
如果前端POST请求发送过来一个form表单,或者是GET请求,则会构建成QueryDict
总结一下: request.data 接收到的是Body中的数据
GET请求可以用request.GET来取
序列化字段
开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。
序列化类的使用
- models
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 .models import *
from rest_framework import serializers
from rest_framework.response import Response
#创建一个序列化类
class BookSerializers(serializers.Serializer):
title = serializers.CharField(max_length=32)
price = serializers.IntegerField()
pub_date = serializers.DateField()
#下面两个是一对多和多对多的字段
#source="publish.name"可以理解为取obj.publish.name
publish = serializers.CharField(source="publish.name")
#SerializerMethodField为多对多服务,与get_authors配合(类似钩子)使用
#可以理解为get_authors(obj),此时authors的返回值取决于get_authors的返回结果
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
temp = []
for obj in obj.authors.all():
temp.append(obj.name)
return temp
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializers(book_list, many=True)
#此处的Response来自rest_framework
return Response(ret.data)
序列化BookSerializers(book_list, many=True)的过程可以简单理解为下面的例子:
temp = []
for obj in book_list:
temp.append({
"title":obj.title,
"price":obj.price,
"pub_date":obj.pub_date,
"publist":obj.publish.name
"authors":get_authors(obj)
})
restframework的Response
在上面的例子中Response把结果从有序字典转换为JSON格式了,其结果为:
[
{
"title": "三体",
"price": 18,
"pub_date": null,
"publish": "人民出版社",
"authors": [
"alex",
"egon"
]
},
{
"title": "go",
"price": 58,
"pub_date": null,
"publish": "清华出版社",
"authors": [
"egon"
]
}
]
ModelSerializer
定义一个ModelSerializer序列化器
- GET请求 类似于ModleForm,将Modle直接序列化
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
#fields = ["id", "title", "pub_time"]
#exclude = ["user"]
#分别是所有字段 包含某些字段 排除某些字段
#depth = 1
#depth 代表找嵌套关系的第几层
#注意:当序列化类MATE中定义了depth时,这个序列化类中引用字段(外键)则自动变为只读
#自定义字段
#下面两个一对多和多对多的字段
#source="publish.name"可以理解为取obj.publish.name
publish = serializers.CharField(source="publish.name")
#SerializerMethodField为多对多服务
#与get_authors配合(类似钩子),可以理解为get_authors(obj),此时authors的返回值取决于get_authors的返回结果
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
temp = []
for obj in obj.authors.all():
temp.append(obj.name)
return temp
结果:
[
{
"id": 1,
"publish": "人民出版社",
"authors": [
"alex",
"egon"
],
"title": "三体",
"price": 18,
"pub_date": null
},
{
"id": 2,
"publish": "清华出版社",
"authors": [
"egon"
],
"title": "go",
"price": 58,
"pub_date": null
}
]
提交post请求,反序列化
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
class BookView(APIView):
def post(self, request):
#request.data中是post请求的数据
bs = BookModelSerializers(data=request.data, many=False)
if bs.is_valid():
#打印正确数据
print(bs.validated_data)
bs.save() #create方法
#返回当前添加的内容
return Response(bs.data)
else:
print(bs.errors)
#返回错误项目信息
return Response(bs.errors)
在Postman中提交JSON数据
{"title": "Python", "price":100, "pub_date": "2012-12-12", "publish":1, "authors":[1,2]}
重写save中的create方法
Serializer提供了.is_valid()和.save()方法 如果是post请求那么.save()就是调用create方法,如果是put请求,那么.save()就是调用update方法 上面我们自定义了publish的返回数据,因此我们要自己写一个create方法
#向http://127.0.0.1:8000/books/发送post请求
{
"title": "go第三版",
"price": 70,
"pub_date": "2017-10-01",
"publish": 1,
"authors": [
1,
2
]
}
views.py
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
publish = serializers.CharField(source="publish.name")
#validated_data是所有接受到的数据,此时已经反序列化为字典
def create(self, validated_data):
#print("validated_data==>", validated_data)
#查看发现{'publish': {'name': '1'},这个name就是上面自定义返回内容是改变的key值
#{'publish': {'name': '1'}, 'title': 'go第三版', 'price': 70, 'pub_date': datetime.date(2017, 10, 1), 'authors': [<Author: alex>, <Author: egon>]}
obj = Book.objects.create(title=validated_data["title"],
price=validated_data["price"],
pub_date=validated_data["pub_date"],
publish_id=validated_data["publish"]["name"])
obj.authors.add(*validated_data["authors"])
return obj
class BookView(APIView):
def post(self, request):
#request.data中是post请求的数据
bs = BookModelSerializers(data=request.data)
if bs.is_valid():
bs.save() #create方法
#返回当前添加的内容
return Response(bs.data)
else:
#返回错误项目信息
return Response(bs.errors)
单条数据的get和put请求
class BookDetailView(APIView):
def get(self, request, id):
book = Book.objects.filter(pk=id).first()
bs = BookModelSerializers(book, context={'request': request})
return Response(bs.data)
def put(self, request, id):
book = Book.objects.filter(pk=id).first()
bs = BookModelSerializers(book, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
超链接API:Hyperlinked
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
publish = serializers.HyperlinkedIdentityField(
view_name="detail_publish", #url中反向解析的别名
lookup_field="publish_id", #对应的字段名称
lookup_url_kwarg="pk", #url中有名分组的名称
)
urls部分:
使用有名分组和反向解析
from app01 import views
urlpatterns = [
......
url(r'^publish/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="detail_publish"),
]
views部分:
注意有名分组中的别名要与视图中的名称对应
class PublishDetailView(APIView):
def get(self, request, pk): #这个pk与url中的有名分组pk对应
publish = Publish.objects.filter(pk=pk).first()
bs = PublishModelSerializers(publish)
return Response(bs.data)
class BookDetailView(APIView):
def get(self, request, id):
book = Book.objects.filter(pk=id).first()
#注意添加context={'request': request}
bs = BookModelSerializers(book, context={'request': request})
return Response(bs.data)
访问
向http://127.0.0.1:8000/books/1发送GET请求 返回结果:
{
"id": 1,
"publish": "http://127.0.0.1:8000/publish/1/",
"title": "三体",
"price": 18,
"pub_date": null,
"authors": [
1,
2
]
}
本文链接:http://nix.pub/article/restframework/