情不知所起,那就从Django rest framework起
过几天就要去实习了,面试结束后,面试官让我去熟悉熟悉 Django 的rest framework,因为公司是前后端分离的,Django原生模版引擎渲染不再适用。学习的过程中,希望记录一些新的体会,另外本篇主要是根据官方文档来学的,因此不会有什么错误,如若有错,请指正,我发红包。
Serialization
中文叫做“序列化”,其实我觉得计算机世界中很多东西根本就没有必要翻译成中文,翻译后反而觉得佶屈聱牙,难以理解。序列化?从字面上来看根本不知道它作用是什么,但看完文档后,一言以蔽之,就是将对象转为字典以便再将其转为Json数据的一个玩意。从形式上看,又有很多跟form相似的地方,为了解释清楚其作用,请看下面的例子。。
这里不再介绍Django的基础,包括创建项目之类的,学习过程中,我们采用如下Model:
class Book(models.Model):
name = models.CharField(max_length=30)
publisher = models.CharField(max_length=30)
author = models.CharField(max_length=30)
version = models.CharField(max_length=20)
def __str__(self):
return self.author + ',《' + self.name + '》,' + self.publisher + ',' + self.version
我们知道,传统上,我们要在View中获取数据库中的对象,需要先用ORM获取一个queryset如下:
books = Book.objects.all() #获取Book表中所有book
book = Book.objects.get(pk=1) #获取主键为1的book
如果想获取book的某个属性:
book_name = book.name
现在我要pk为1书的所有信息,key 放属性名称,如name,publisher... value放值,返回给我一个Json。如下:
'{"name":"Python Cookbook","publisher":"人民邮电大学出版社","author":"David Beazley Brian K.Jones","version":"第3版"}'
如果不用Serialization,那么我们会在View里面写:
import json
book = Book.objects.get(pk=1)
output = {
'name':book.name,
'publisher':book.publisher,
'author':book.author,
'version':book.version
}
json.dumps(output)
当然可行,但是你想这么写是不是太啰嗦了,而且极其不优雅,违反了DRY(Don't repeat yourself)的原则。
但是我们引入Serialization怎么解决呢?
首先在models.py同级的目录下创建文件serializers.py,在里面创建一个serializer对象:
from second_book.models import Book
from rest_framework import serializers
class BookSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Book
fields = ('name', 'publisher', 'author', 'version')
这里的HyperlinkedModelSerializer以后再解释,看到这里学过form应该会突然龙躯一震,这货太像form了吧,我也觉得。另外,想用rest framework必须在settings.py里面的INSTALLED_APP加上rest_framework。接下来我们看怎么实现之前我们提到的这个需求——
from second_book.serializers import BookSerializer
book = Book.objects.get(pk=1)
data = BookSerializer(book).data
json.dumps(data)
很明显,这样写清爽多了。不过生产环境中,一般用byte来传输,利用rest framework提供的原生api,对data进行如下处理:
from rest_framework.renderers import JSONRenderer
content = JSONRenderer().render(serializer.data)
print(content)
# b'{"name":"Python Cookbook","publisher":"\xe4\xba\xba\xe6\xb0\x91\xe9\x82\xae\xe7\x94\xb5\xe5\xa4\xa7\xe5\xad\xa6\xe5\x87\xba\xe7\x89\x88\xe7\xa4\xbe","author":"David Beazley Brian K.Jones","version":"\xe7\xac\xac3\xe7\x89\x88"}'
另外,将Json反序列化成对象,也会非常简单,如下:
from django.utils.six import BytesIO
stream = BytesIO(content)
data = JSONParser().parse(stream)
serializer = BookSerializer(data=data)
serializer.is_valid() # True
serializer.save()
这里serializer跟form就更像了,form也有is_valid()和save()方法,不是吗?
另外值得一提的是,serializer对象不仅可以传入模型实例,如刚才的book,也可以传入queryset,示例如下:
BookSerializer(Book.objects.all(),many=True).data
如何在View中加入Serializer
首先导入模块:
from second_book.models import Book
from rest_framework.parsers import JSONParser
from second_book.serializers import BookSerializer
from django.http import HttpResponse, JsonResponse
如果希望对Book整个类的所有条目进行操作,那么:
def book_list(request):
if request.method == 'GET':
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = BookSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
else:
return JsonResponse(serializer.errors, status=400)
如果对Book中单个条目进行操作,那么:
def book_detail(request, pk):
try:
book = Book.objects.get(pk=pk)
except Book.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
serializer = BookSerializer(book)
return JsonResponse(serializer.data)
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = BookSerializer(book, data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
else:
return JsonResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
book.delete()
return HttpResponse(status=204)
这里面要注意,如果仅返回状态码,则直接使用HttpResponse即可,JsonResponse一定要带上一个Json格式的字符串,不可以只返回状态码。
网友评论