在开发Web应用中,有两种应用模式:
前后端不分离[客户端看到的内容和所有界面效果都是由服务端提供出来的
前后端分离【把前端的界面效果(html,css,js分离到另一个服务端,python服务端只需要返回数据即可)】
前端形成一个独立的网站,服务端构成一个独立的网站
接口实现过程中,会存在幂等性。所谓幂等性是指代客户端发起多次同样请求时,是否对于服务端里面的资源产生不同结果。如果多次请求,服务端结果还是一样,则属于幂等接口,如果多次请求,服务端产生结果是不一样的,则属于非幂等接口。
请求方式 | 是否幂等 | 是否安全 |
---|---|---|
GET | 幂等 | 安全 |
POST | 不幂等 | 不安全 |
PUT/PATCH | 幂等 | 不安全 |
DELETE | 幂等 | 不安全 |
api接口开发,最核心最常见的一个代码编写过程就是序列化,所谓序列化就是把数据转换格式。常见的序列化方式:
json,pickle,base64,….
序列化可以分两个阶段:
序列化: 把我们识别的数据转换成指定的格式提供给别人。
例如:我们在django中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。
反序列化:把别人提供的数据转换/还原成我们需要的格式。
例如:前端js提供过来的json数据,对于python而言json就是字符串,我们需要进行反序列化换成字典,然后接着字典再进行转换成模型对象,这样我们才能把数据保存到数据库中。
核心思想: 大量缩减编写api接口的代码
Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
中文文档
GitHub
DRF需要以下依赖:
DRF是以Django子应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)
前提是已经安装了django,建议安装在虚拟环境
# conda create -n drfdemo python=3.8
# conda activate drfdemo
# pip install django -i https://pypi.douban.com/simple
# conda install pymysql
pip install djangorestframework -i https://pypi.douban.com/simple
# 因为我们需要接下来,需要开发api接口肯定要操作数据,所以安装pymysql
pip install pymysql -i https://pypi.douban.com/simple
linux 复制 shift+insert
cd ~/Desktop
django-admin startproject drfdemo
使用pycharm打开项目,设置虚拟环境的解析器,并修改manage.py中的后缀参数。
在settings.py的INSTALLED_APPS中添加’rest_framework’。
INSTALLED_APPS = [
...
'rest_framework',
]
接下来就可以使用DRF提供的功能进行api接口开发了。在项目中如果使用rest_framework框架实现API接口,主要有以下三个步骤:
接下来,我们快速体验下四天后我们学习完成drf以后的开发代码。接下来代码不需要理解,看步骤。
配置数据库连接并初始化pymysql
settings.py
,代码:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'school', # 数据库名字
'PORT': 3306, # 数据库端口
'HOST': '127.0.0.1', # 数据库主机地址
'USER': 'root', # 数据库用户名
'PASSWORD': '123', # 数据库用户密码
}
}
drfdemo.__init__.py
,代码:
import pymysql
pymysql.install_as_MySQLdb()
创建students子应用,并在setings.py中进行注册rest_framework和students子应用
python manage.py startapp students
settings.py,代码:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'students',
]
from django.db import models
# Create your models here.
class Student(models.Model):
SEX_OPTION = (
(0, "保密"),
(1, "男"),
(2, "女"),
)
name = models.CharField(max_length=20, verbose_name="姓名", help_text="请输入一个正常的人名!")
age = models.SmallIntegerField( verbose_name="年龄", help_text="请输入一个人的年龄,范围在1-100之间~")
sex = models.SmallIntegerField(choices=SEX_OPTION, verbose_name="性别")
classmate = models.CharField(db_column="class", max_length=15, verbose_name="班级")
description = models.TextField(null=True, blank=True, verbose_name="个性签名")
class Meta:
db_table = "db_student"
verbose_name = "学生信息"
verbose_name_plural = verbose_name
例如,在django项目中创建学生子应用。
python manage.py startapp students
在syudents应用目录中新建serializers.py用于保存该应用的序列化器。
创建一个StudentModelSerializer用于序列化与反序列化。
from rest_framework import serializers
# 序列化基类
# serializers.Serializers
# serializers.ModelSerializer
from .models import Student
class StudentModelSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = "__all__"
# fileds = ["id","name"]
__all__
指明包含所有字段在students应用的views.py中创建视图StudentModelViewSet,这是一个视图集合。
from rest_framework.viewsets import ModelViewSet
from .models import Student
from .serializers import StudentModelSerializer
# Create your views here.
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
在students应用的urls.py中定义路由信息。
from django.urls import path
from . import views
urlpatterns =[
]
from rest_framework.routers import SimpleRouter,DefaultRouter
router = DefaultRouter() # 可以处理视图的路由器
router.register("stu", viewset=views.StudentModelViewSet, basename="stu") # 向路由器中注册视图集
urlpatterns += router.urls # 将路由器中的所以路由信息追到到django的路由列表中
运行当前程序(与运行Django一样)
python manage.py runserver
在浏览器中输入网址127.0.0.1:8000,可以看到DRF提供的API Web浏览页面
1)点击链接127.0.0.1:8000/stu/students 可以访问获取所有数据的接口,
2)在页面底下表单部分填写学生信息,可以访问添加新学生的接口,
点击POST后,返回页面信息
3)在浏览器中输入网址127.0.0.1:8000/stu/students/137/,可以访问获取单一学生信息的接口(id为5的学生),
4)在页面底部表单中填写学生信息,可以访问修改学生的接口:
点击PUT,返回页面信息
5)点击DELETE按钮,可以访问删除学生的接口:
点击删除以后,返回页面
作用:
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能
Django REST framework中的Serializer使用类来定义,序列化器类必须直接或间接继承自rest_framework.serializers.Serializer。Serializer有个子类叫:ModelSerializer
接下来,为了方便演示序列化器的使用,我们先创建一个新的子应用sers
python manage.py startapp sers
注册子应用,并创建urls子路由文件,最后在总路由中注册子路由。
settings.py
,代码:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'students',
'sers', # 序列化器
]
sers.urls,代码:
from django.urls import path
from . import views
urlpatterns =[
]
drfdemo.urls,代码:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('students/', include("students.urls")),
path('sers/', include("sers.urls")),
]
我们已有了一个数据库模型类,所以我们就基于这个模型类来完成序列化器的学习。students.models,代码:
from django.db import models
# Create your models here.
class Student(models.Model):
SEX_OPTION = (
(0, "保密"),
(1, "男"),
(2, "女"),
)
name = models.CharField(max_length=20, verbose_name="姓名", help_text="请输入一个正常的人名!")
age = models.SmallIntegerField( verbose_name="年龄", help_text="请输入一个人的年龄,范围在1-100之间~")
sex = models.SmallIntegerField(choices=SEX_OPTION, verbose_name="性别")
classmate = models.CharField(db_column="class", max_length=15, verbose_name="班级")
description = models.TextField(null=True, blank=True, verbose_name="个性签名")
class Meta:
db_table = "db_student"
verbose_name = "学生信息"
verbose_name_plural = verbose_name
我们想为这个模型类提供一个序列化器,可以定义如下:
sers.serializers,代码:
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
class StudentSerializer(serializers.Serializer):
"""学生信息序列化器"""
# 1. 声明在请求和响应过程中,需要进行数据转换的字段
id = serializers.IntegerField()
name = serializers.CharField()
age = serializers.IntegerField()
sex = serializers.IntegerField()
description = serializers.CharField()
# 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息
# 3. 验证代码
# 4. 编写模型的添加和更新代码
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。 serializer是独立于数据库之外的存在。
Serializers常用字段类型:
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format=‘hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3) 'int' - 如: "123456789012312313134124512351145145114" 4) 'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol=‘both’, unpack_ipv4=False, options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
选项参数:
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空,是否为空字符串 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用参数:
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器,自定义验证函数 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称, 如果没有设置,则会出现英文的字段名或者模型中verbose_name |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 如果没有设置,则会出现英文的字段名或者模型中help_text |
定义好Serializer类后,就可以创建Serializer对象了。
Serializer的构造方法为:
Serializer(instance=None, data=empty, many=True/False, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)转换数据可以是一条也可以是多条,如果多条数据,则需要通过many=True来设置。
4)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
serializer = StudentSerializer(模型, context={
'request': request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
序列化器的使用分两个阶段:
1) 先查询出一个学生对象
from students.models import Student
# student = Student.objects.get(id=3)
student = Student.objects.first()
2) 构造序列化器对象
from .serializers import StudentSerializer
# serializer = StudentSerializer(instance=student)
serializer = StudentSerializer(instance=student)
3)获取序列化数据
通过data属性可以获取序列化后的数据
serializer.data
# {'id': 4, 'name': '小张', 'age': 18, 'sex': True, 'description': '猴赛雷'}
视图代码:
"""因为我们现在刚开始学习drf的序列化器,还没有学到drf的视图类,所以暂时先使用django原生提供的django.views.View"""
from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class Student1View(View):
def get1(self,request):
"""
使用序列化器对数据进行序列化格式转换,提供给客户端
序列化器的序列化阶段
"""
"""序列化一条数据"""
# 对数据进行查询
student = Student.objects.first()
"""实例化序列化器得到序列化器对象"""
# StudentSerializer(instance=student) # instance是第一个参数,可以不填
serializer = StudentSerializer(student)
# print(f"serializer={serializer}")
# 获取到格式转换后的数据,data内转换
# print(f"serializer.data={serializer.data}")
return JsonResponse(serializer.data)
4)如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
def get(self,request):
"""使用序列化器对数据进行序列化格式转换,提供给客户端
序列化器的序列化阶段
"""
"""序列化多条数据"""
# 1. 对数据进行查询
student_list = Student.objects.all()
# 2. 实例化序列化器对象,并传入要转换的数据
serializer = StudentSerializer(student_list,many=True)
print(serializer.data)
"""
[
OrderedDict([('id', 1), ('name', '赵华'), ('age', 22), ('sex', 1), ('description', '对于勤奋的人来说,成功不是偶然;对于懒惰的人来说,失败却是必然。')]),
OrderedDict([('id', 2), ('name', '程星云'), ('age', 20), ('sex', 1), ('description', '人生应该如蜡烛一样,从顶燃到底,一直都是光明的。')]),
...
]
OrderedDict 是python内置的高级数据类型,叫有序字典。主要为了解决基本数据类型的dict在存储数据时的随机性问题。
OrderedDict 的使用和基本类型的dict是一模一样的。可以保证,写入的数据格式顺序在读取时保持一致。
from collections import OrderedDict
"""
return JsonResponse(serializer.data, safe=False)
注意:序列化器的序列化器阶段,不仅可以转换模型对象的数据格式,只要是python中的对象,属性对应序列化器中的字段,都可以完成转换成字典或者列表。
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用序列化器对象提供的**is_valid()**方法进行调用序列化内部预先写好的验证代码,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息(字典格式),包含了字段和字段的错误提示。如果是非字段错误,可以通过修改REST framework提供的配置选项NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取验证后的数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,当然这个设置本身就是一种验证行为。
如我们前面定义过的StudentSerializer
sers.serializers,代码:
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
class StudentSerializer(serializers.Serializer):
"""学生信息序列化器"""
# 1. 声明在请求和响应过程中,需要进行数据转换的字段
# read_only=True 表示用户提交数据进行反序列化时,序列化器不会启用这个字段,而是在序列化器进行序列化转换数据给客户端时才启用这个字段
id = serializers.IntegerField(read_only=True)
# required=True 表示用户移交数据时,这个字段时必填的
# max_length=20 表示当前字符串字段最大长度为20个字符
name = serializers.CharField(required=True, max_length=20)
classmate = serializers.CharField(required=True, max_length=3)
age = serializers.IntegerField()
sex = serializers.IntegerField()
# required=False 表示当前字段,用户提交数据时,可以不提交这个字段的数据
# default 表示当前字段,用户提交数据时,没有值的情况下,采用这个值作为默认值传递验证结果的返回值中。
description = serializers.CharField(required=False, default="这家伙很懒,什么也没写!")
# 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息
# 3. 验证代码
# 4. 编写模型的添加和更新代码
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
sers.views,代码:
def get(self,request):
"""反序列化一般就是在用户添加数据或更新数据时使用"""
"""添加数据时的反序列化"""
# 模拟用户提交过来的数据
params = {
"name": "王小明",
"age": 17,
"sex": 1,
}
# 1. 实例化序列化器
serializer = StudentSerializer(data=params)
# raise_exception=True 表示在反序列化验证数据失败以后,由drf直接抛出异常,返回错误提示给客户端
# drf将来提供的视图类会自动把错误信息转换成json数据提供给客户端
# serializer.is_valid(raise_exception=True)
ret = serializer.is_valid()
print(f"验证结果={
ret}") # 验证数据通过则True,否则为False
i