Django REST framework是一套基于Django的REST框架,是一个用于构建Web API的功能强大且灵活的工具包。
Representational State Transfer(REST),是一种架构样式,定义了一套用于创建WEB服务的约束。当前WEB开发趋势就是前端层出不穷,为了保证一个后台同时适用于多个前端,需要一种统一的机制或API,而RESTful API是目前前后端分离的最佳实践。
虽然Django中可以通过DTL(Django Template Language)来实现PC端的显示,但却无法支持如Android端、ios端。而且Django只能依赖DTL实现PC端的显示。
要实现一套后台适应多个前端,就必须使用前后端分离技术,因此就要使用RESTful API,而Django REST框架正是基于Django的RESTful API。
通过如下命令安装REST 框架:
$ pip install djangorestframework
如果没有安装Python,则需要安装Python和Django:
$ sudo apt-get install python3.6
$ sudo apt-get install python3-pip
$ pip install Django
序列化,是指将复杂的QuerySet和Model类型转换成Python基本数据类型,从而将这些基本数据类型以JSON的形式响应给客户端。
反序列化则和序列化相反,是指将Http请求中传入的JSON数据转换成复杂的数据类型,从而保存在数据库中。
在REST Framework中,提供了多个用于序列化操作的类,但常用的也就如下两个:
Serializer:进行序列化基本的类;
ModelSerializer:继承于Serializer,内部实现了通用的序列化逻辑,其中包含了与Model字段对应的字段,可以快速对Model进行序列化。
使用时需要导入对应模块:
from rest_framework import serializers
接下来我们就分别看看这两个序列化操作的类。
Serializer进行序列化的基本格式如下:
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
# 指定要序列化的字段
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
# 用于反序列化时创建一个Model实例
def create(self, validated_data):
return Comment(**validated_data)
# 用于反序列化时更新一个Model实例
def update(self, instance, validated_data):
# ...
instance.email = validated_data.get('email',instance=emial)
# ...
return instance
接下来我们看看在REST框架中如何对一个Model进行序列化操作。
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=40)
age = models.IntegerField()
number = models.IntegerField(unique=True)
date = models.DateField()
在app/下创建serializer.py文件
from rest_framework import serializers
from .models import Student
class StudentSerializer(serializers.Serializer):
# 定义要序列化的字段
name = serializers.CharField(read_only=True)
age = serializers.IntegerField(read_only=True)
number = serializers.IntegerField(read_only=True)
date = serializers.DateField(read_only=True)
# 在反序列化时,当save()调用时生成一个Student对象
def create(self, validated_data):
# 会将生成的实例保存到数据库
return Student.objects.create(**validated_data)
# 在反序列化时,当save()调用时更新Student对象
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.age = validated_data.get('age', instance.age)
instance.number = validated_data.get('number', instance.number)
instance.date = validated_data.get('date', instance.date)
instance.save() #确保保存在数据库
return instance
这个序列化类中有两部分:
serializer.save()
时用于生成Model对象的create()
和update()
方法,这两方法负责将JSON类型的数据转换成Python类型的数据,即反序列化的过程。整个序列化类的实现就这么简单,接下来我们还需要对这个序列化类进行测试。
测试Serializer有两种方式,一种是在Django Shell下进行测试,还有一种就是直接创建一个View,通过http请求进行测试,如果掌握了如何创建view,那么请直接在View中进行吧!
使用python manage.py shell
进入Django Shell中:
>>> from Students.models import Student # 导入对应module
>>> from Students.serializers import StudentSerializer
>>> stu = Student(name='zhangsan',age=21,number=1,date='2018-4-23') #创建一个Model实例
>>> stu.save() # 将该实例存入数据库
>>> serializer = StudentSerializer(stu) #进行序列化
>>> serializer.data # 查看序列化后的结果
{'name': 'zhangsan', 'age': 21, 'number': 1, 'date': '2018-4-23'}
现在将Student实例转换成了Python中的dict类型,接下来将dict类型转换为JSON数据:
>>> from rest_framework.renderers import JSONRenderer #JSONRenderer将数据渲染称JSON格式
>>> content = JSONRenderer().render(serializer.data)
>>> content
b'{"name":"zhangsan","age":21,"number":1,"date":"2018-4-23"}'
>>>
反序列化类似,第一步是将JSON形式数据转换为流的形式,并将流数据转化为python本地数据类型:
>>> from django.utils.six import BytesIO
>>> from rest_framework.parsers import JSONParser
>>> stream = BytesIO(content) # 将JSON数据转换为流的形式
>>> data = JSONParser().parse(stream) # JSONParser将解析流中的JSON数据,得到Python的类型数据
>>> data
{'name': 'zhangsan', 'age': 21, 'number': 1, 'date': '2018-4-23'} # 一个dict类型的数据
>>>
然后将Python本地类型转换为实例,保存在数据库中:
>>> serializer = StudentSerializer(data=data)
>>> serializer.is_valid() # 验证是否有效
>>> True
>>> serializer.save() # 将保存在数据库中
该例中是序列化了一个Model对象,如果要序列化由Model.objects.all()
返回的一个QuerySet实例,在设置serializer时添加一个参数:
>>> serializer = StudentSerializer(Student.objects.all(), many=True)
>>> serializer.data
>>>
虽然这种方式略显麻烦,但对于初学者来说,掌握Django shell还是很有用的。
如果对View相关知识了解,那么可以非常方便的在View中通过Http请求进行验证,如下是通过GET请求和POST请求用于验证Serializer:
from rest_framework import views
from rest_framework.response import Response
from rest_framework import status
from . import models
from .serializers import StudentSerializer
# Create your views here.
class show(views.APIView):
def get(self, request):
"""
get方法处理GET请求
"""
try:
Student = models.Student.objects.all()
# Student是一个QuerySet,而不是一个Model对象,因此需要设置many=True
serializer = StudentSerializer(Student, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
except Student.DoesNotExist:
return Response(serializer.data, status=status.HTTP_404_NOT_FOUND)
def post(self, request):
"""
post方法处理POST请求
"""
# request.data是请求体中经过解析后的数据
serializer = StudentSerializer(data=request.data)
if serializer.is_valid(): # 检验是否有效
serializer.save() # 将会调用Serializer中的create(),并保存在数据库中
# serializer.data是序列化后的原始数据
# rest_framework.status中定义了常见返回值,如404,200...
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
关于DRF的View相关部分会在之后的文章中详细总结。
在调用serializer.save()
时,会创建或者更新一个Model实例(调用create()
或update()
创建),具体根据序列化类的实现而定,如:
# .save() will create a new instance.
serializer = StudentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = StudentSerializer(comment, data=data)
Serializer中的create()
和update()
方法用于创建生成一个Model实例,在使用Serializer时,如果要保存反序列化后的实例到数据库,则必须要实现这两方法之一,生成的实例则作为save()
返回值返回。方法属性validated_data
表示校验的传入数据。
当反序列化时,在调用Serializer.save()
之前必须要使用is_valid()
方法进行校验,如果校验成功返回True,失败则返回False,同时会将错误信息保存到serializer.errors
属性中。
serializer.data
中保存了序列化后的数据。
当serializer.is_valid()
进行校验后,如果校验失败,则将错误信息保存到serializer.errors
属性中。
在定义Model时,我们通过models.
获取了各种不同的字段,作为数据库中表的一个列。而在Serializer中,也需要通过`serializers.
的形式获取对应Model的字段,用来在JSON数据和Python数据类型之间进行转换,此外还可以根据Field中传入的属性进行校验、设置默认值。以下对常用Serializer的Field进行整理。
使用时,需要导入所在模块:
from rest_framework import serializers
对应models.CharField
,同时如果指定长度,还会负责校验文本长度。
max_length
:最大长度;min_length
:最小长度;allow_blank=True
:表示允许将空串做为有效值,默认False;对应models.EmailField
,验证是否是有效email地址。
对应models.IntegerField
,代表整数类型
对应models.FloatField
,代表浮点数类型
对应models.DateTimeField
,代表时间和日期类型。
format='YYYY-MM-DD hh:mm'
:指定datetime输出格式,默认为DATETIME_FORMAT
值。需要注意,如果在 ModelSerializer
和HyperlinkedModelSerializer
中如果models.DateTimeField
带有auto_now=True
或者auto_add_now=True
,则对应的serializers.DateTimeField
中将默认使用属性read_only=True
,如果不想使用此行为,需要显示对该字段进行声明:
class CommentSerializer(serializers.ModelSerializer):
created = serializers.DateTimeField()
class Meta:
model = Comment
对应models.FileField
,代表一个文件,负责文件校验。
max_length
:文件名最大长度;allow_empty_file
:是否允许为空文件;对应models.ImageField
,代表一个图片,负责校验图片格式是否正确。
max_length
:图片名最大长度;allow_empty_file
:是否允许为空文件;如果要进行图片处理,推荐安装Pillow:
pip install Pillow
这是serializers中特有的Field,它不根据用户提交获取值,而是从默认值或可调用的值中获取其值。一种常见的使用场景就是在Model中存在user_id
作为外键,在用户提交时,不允许提交user_id
,但user_id
在定义Model时又是必须字段,这种情况下就可以使用HiddenField提供一个默认值:
class LeavingMessageSerializer(serializers.Serializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
所谓公共参数,是指对于所有的serializers.
都可以接受的参数。以下是常见的一些公共参数。
read_only=True
表示该字段为只读字段,即对应字段只用于序列化时(输出),而在反序列化时(创建对象)不使用该字段。默认值为False。
write_only=True
表示该字段为只写字段,和read_only
相反,即对应字段只用于更新或创建新的Model时,而在序列化时不使用,即不会输出给用户。默认值为False。
required=False
表示对应字段在反序列化时是非必需的。在正常情况下,如果反序列化时缺少字段,则会抛出异常。默认值为True。
给字段指定一个默认值。需要注意,如果字段设置了default
,则隐式地表示该字段已包含required=False
,如果同时指定default
和required
,则会抛出异常。
allow_null=True
表示在序列化时允许None
作为有效值。需要注意,如果没有显式使用default
参数,则当指定allow_null=True
时,在序列化过程中将会默认default=None
,但并不会在反序列化时也默认。
一个应用于传入字段的验证函数列表,如果验证失败,会引发验证错误,否则直接是返回,用于验证字段,如:
username = serializers.CharField(max_length=16, required=True, label='用户名',
validators=[validators.UniqueValidator(queryset=User.objects.all(),message='用户已经存在')])
验证时错误码和错误信息的一个dict,可以指定一些验证字段时的错误信息,如:
mobile= serializers.CharField(max_length=4, required=True, write_only=True, min_length=4,
label='电话', error_messages={
'blank': '请输入验证码',
'required': '该字段必填项',
'max_length': '验证码格式错误',
'min_length': '验证码格式错误',
})
一个键值对,用于控制字段如何渲染,最常用于对密码进行密文输入,如:
password = serializers.CharField(max_length=16, min_length=6, required=True, label='密码',
error_messages={
'blank': '请输入密码',
'required': '该字段必填',
'max_length': '密码长度不超过16',
'min_length': '密码长度不小于6',
},
style={'input_type': 'password'}, write_only=True)
一个简短的文本字串,用来描述该字段。
一个文本字串,可用作HTML表单字段或其他描述性元素中字段的描述。
ModelSerializers
继承于Serializer
,相比其父类,ModelSerializer自动实现了以下三个步骤:
create()
方法和update()
方法。使用ModelSerializer方式如下:
class StudentSerializer(serializers.ModelSerializer):
class Meta:
# 指定一个Model,自动检测序列化的字段
model = StudentSerializer
fields = ('id', 'name', 'age', 'birthday')
相比于Serializer,可以说是简单了不少,当然,有时根据项目要求,可能也会在ModelSerializer中显示声明字段,这些在后面总结。
该属性指定一个Model类,ModelSerializer会根据提供的Model类自动检测出需要序列化的字段。默认情况下,所有Model类中的字段将会映射到ModelSerializer类中相应的字段。
如果不希望对Model中所有的字符进行序列化,可以在fields属性中显示指定要进行序列化的字段。