在开发web应用中,有俩种应用模式:
1. 前后端不分离( 客户端看到的内容和所有界面效果都是由服务器提供的 )
这种情况下前端页面中会出现很多涉及到服务端的模板语法
2. 前后端分离( 把前端的界面效果(html 陈述事实就是 分离到另一个项目中, python服务端只需要返回数据即可)
前端形成一个独立的网站,服务端构成一个独立的网站.
django,一般是做web网站,如果可利用django实现前后端分离,则django就可以完成地铁站的运营调度系统,路由的终端系统,pos机的服务端系统,游戏的服务端后台,软件服务端后台.
为了在团队内部形成共识,防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范,而且这种'规范能够让后端写的接口,用途一目了然,减少成本.
目前市面上大部分公司开发人员使用的接口服务框架主要有:restful rpc soap
服务端提供单一的请求数据的api地址:http://api.renran.cn/
post 请求
action=get_all_student&class=301&sex=1
特点:
优点:不需要在意当前操作是什么http请求,也不需要操作url地址的编写,对接简单.
缺点: 接口多了,对应的函数名和参数就多了,前端在请求api接口是,就会比较困难,也容易出现重复的接口.
把后端的所有的数据/文件都看成资源.
那么接口请求数据,本质上来说就是对资源的操作.
web项目中操作资源,就是增删改查,所以要求在地址栏中声明要操作的资源是什么,然后通过http请求动词来说明对资源进行那种一种操作.
POST http://www.renran.cn/api/students/ 添加学生数据
GET http://www.renran.cn/api/students/ 获取所有学生
DELETE http://www.renran.cn/api/students/
PUT http://www.renran.cn/api/students/
PATCH http://www.renran.cn/api/students/
特点:
优点: 维护开发简单, 可以保证后期的开发不会出现太多重复接口.
缺点: 有部分接口不会明确的增删改查这种区分的,所以会出现一些不伦不类的接口.会因为这些语语意不明的接口,导致后期产生过高的维护成本.
因为restful 把对资源的操作都理解成了曾删改查,建议使用http,所以restful 接口天生局限于web开发.
REST全称是Representaional State Transfer 中文的意思是表述(编者注:通常译作为表征) 性状态转移.它首次出现在2000年roy Fielding的博士论文中
RESTful是一种定义Web API接口的设计风格,尤其适用于前后端分离的应用模式中。
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
请求方法
请求地址
后端操作
GET
/students
获取所有学生
POST
/students
增加学生
GET
/students/
获取主键为pk的学生
PUT
/students/
修改主键为pk的学生
DELETE
/students/
删除主键为pk的学生
事实上,我们可以使用任何一个框架都可以实现符合restful规范的API接口
参考文档::http://www.runoob.com/w3cnote/restful-architecture.html
接口实时过程中.存在幂等性.所谓幂等性是指代客户端发起多次请求是否对服务端里面的资源产生不同结果.如果多次请求,服务端的结果都是一样的,则属于幂等接口.反之则不属于幂等接口. 在http请求get/put/patch/delete都属于幂等性接口,post属于非幂等接口。
为什么要考虑幂等性?主要就是接口操作的安全性问题。
delete /api/students/1
get /api/students/
post /api/students/
api接口开发,是核心最常见的一个过程就是序列化,所谓序列化就是把 数据转格式 ,序列化可以分为俩个阶段: 序列化 和反序列化
序列化: 把我们可以识别的数据转换成指定的格式提供给别人.
例如: 我们在django中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用.所以我们需要把数据进行序列化,变成字符串或者json数据,提供给前端或者其他平台.
反序列化: 被别人提供的数据转换/还原成我们需要的格式.
例如: 前端js提供过来的json数据,对于python而言就是字符串,我们需要 进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中.
核心思想:缩减编写api接口的代码
djangoREST framework 是一个建立在Django基础之上的web 应用开发框架,本质上就是一个内置在django 里面的子应用,可以快速的开发REST API接口应用.
在REST framework中, 提供了序列化器对象Serialzier的定义, 可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供了丰富的类视图,扩展类,视图集来简化视图的编写工作.RESTframework 还提供了认证, 权限, 限流 , 过滤 , 分页, 接口文档等功能支持.REST framework 提供了一个用于测试API接口的可视化web界面( 可以浏览器直接访问接口吗drf的api
接口测试页面非常美观)
中文文档:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework
github: https://github.com/encode/django-rest-framework/tree/master
特点:
DRF 需要依赖:
Python(2.7,3.2 以上)
django(1.10,1.11,2.0 以上)
DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的django环境而无需从新创建,(若没有django环境,需要先创建环境安装Django)
前提是安装可django,建议安装在虚拟环境
windows的复制在linux终端是无效的,在ububtu终端下粘贴的快捷键是 shift+insert
# mkvirtualenv drfdemo -p python3
pip install djangorestframework -i https://pypi.douban.com/simple
pip install pymysql -i https://pypi.douban.com/simple
linux对的终端下粘贴内容快捷键: shift+insert
cd ~/Desktop
django-admin startproject drfdemo
pycharm打开项目,设置虚拟环境的解释器,
使用pycharm打开项目, 设置虚拟环境的解释器,并修改manage.py中的后缀参数>
在settings.py的INSTALLEN_APPS中添加rest_framework
INSTALLED_APPS = [
…
'rest_framework',
]
接下来就可以使用DRF提供的功能进行api接口开发了. 在项目中如果使用rest_framework
框架实现API接口,主要有以下三步骤:
# 项目根目录下创建子应用,用于展示当前例子。
python manage.py startapp students
创建模型操作类
子应用的models.py文件中创建模型对象.
from django.db import models
class Student(models.Model):
# 表字段声明
# 字段名=models.数据类型(字段约束)
name = models.CharField(null=False, max_length=32, verbose_name="姓名")
sex = models.BooleanField(default=True, verbose_name="性别")
age = models.IntegerField(verbose_name="年龄")
class_num = models.CharField(max_length=5, verbose_name="班级编号")
description = models.TextField(max_length=1000, verbose_name="个性签名")
# 表信息
class Meta:
# 设置表名
db\_table="tb\_students"
verbose\_name="学生"
verbose\_name\_plural=verbose\_name
# 模型的操作方法
def \_\_str\_\_(self):
return self.name
为了方便测试,我们可以先创建一个数据库.
create database students charset=utf8;
执行数据迁移
把students子应用添加到ISTALLL_APPS中
初始化数据库连接
安装pymysql
pip install pymysql
主引用__init__.py 设置使用pymysql作为数据库驱动
import pymysql
pymysql.install_as_MySQLdb()
settings.py 配置文件中设置mysql的账号密码
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# },
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "students",
"HOST": "127.0.0.1",
"PORT": 3306,
"USER": "root",
"PASSWORD":"123",
},
}
终端下,执行数据迁移.
python manage.py makemigrations
python manage.py migrate
错误列表
# 执行数据迁移 python manage.py makemigrations 报错如下:
解决方案:
注释掉 backends/mysql/base.py中的35和36行代码。
# 执行数据迁移发生以下错误:
解决方案:
backends/mysql/operations.py146行里面把decode换成encode:
在students应用目录中新建serizlizers.py用于保存该应用的序列化器.
创建一个StudebtModelSerializer 用于序列化与反序列化
# 创建序列化器类,回头会在试图中被调用
from rest_framework import serializers
from .models import Student
class StudentModelSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = "__all__"
model指明该序列化器处理的数据字段从模型类Bookinfo参数生成
fields 之明该序列化器包含模型类中的那些字段,all 指明包含所有字段
在students应用的views.py中创建视图
StudentsViewSet, 这是一个视图集合.
from rest_framework.viewsets import ModelViewSet
from .models import Student
from .serializers import StudentModelSerializer
class StudentViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
queryset指明该视图集在查询数据时使用的查询集
serializer_class 指明该视图在进行序列化或反序列化时使用的序列化器
在输入端问题是应用的 urls.py 中定义路由信息.
from . import views
from rest_framework.routers import DefaultRouter
urlpatterns = []
router = DefaultRouter() # 可以处理视图的路由器
router.register('students', views.StudentViewSet) # 向路由器中注册视图集
urlpatterns += router.urls # 将路由器中的所以路由信息追到到django的路由列表中
最后把students子应用中的路由文件加载到总路由文件中
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path("student/",include("students.urls")),
]
运行当前程序( 与运行Django一样)
python manage.py runserver
在浏览器中输入网址127.0.0.1:8000,可以看到DRF提供的API Web浏览页面:
1 ) 点击链接27.0.0.1:8000/stu/students 可以访问获取所有数据的接口,呈现如下页面:
2 ) 在页面底下表单部分填写学生信息, 可以访问添加新学生的接口 保存学生信息:
点击POST后, 返回如下页面信息:
3 ) 在浏览器中输入网址127.0.0.1:8000/stu/students/5/,可以访问获取单一学生信息的接口(id为5的学生),呈现如下页面:
4 ) 在页面底部表单中填写学生信息, 可以反问修改学生的接口:
点击PUT ,返回如下页面信息:
5 ) 点击DELETE按钮, 可以访问删除学生的接口:
返回, 如下页面:
作用:
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
Django REST framework中的Serializer 使用类来定义, 必须继承自rest_framework.serializers.Serializer。
接下来,为了方便演示序列化器的使用,我们先创建一个新的子应用sers
python manage.py startapp sers
我们有了一个数据库模型类students/Student
from django.db import models
class Student(models.Model):
# 模型字段
name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:账号不能为空!")
sex = models.BooleanField(default=True,verbose_name="性别")
age = models.IntegerField(verbose_name="年龄")
class_null = models.CharField(max_length=5,verbose_name="班级编号")
description = models.TextField(verbose_name="个性签名")
class Meta:
db\_table="tb\_student"
verbose\_name = "学生"
verbose\_name\_plural = verbose\_name
我们想为这个模型类提供一个序列化器. 可以定义如下
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
"""学生信息序列化器"""
# 1. 需要进行数据转换的字段
id = serializers.IntegerField()
name = serializers.CharField()
age = serializers.IntegerField()
sex = serializers.BooleanField()
description = serializers.CharField()
# 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息
# 3. 验证代码
# 4. 编写添加和更新模型的代码
注意:serializer不是只能为数据库模型来定义,也可以为非数据模型类的数据定义. serializer 是独立于数据库之外的存在.
字段
字段构造方式
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(max_length=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页面时,显示的字段名称
help_text
用于HTML展示API页面时,显示的字段帮助提示信息
定义好Serializer类后, 就可以创建Serializer对象了.
Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
说明:
serializer = AccountSerializer(account, context={'request': request})
1 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要在视图中进行调用才可以.
2 序列化器无法直接接收数据, 需要在视图中创建序列化对象时使用的数据传递过来.
3 序列化器的字段声明类似于前面使用过的表单系统.
4 开发restful Api时 , 序列化器会帮我们把模型数据转换成字典.
5 drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.
序列化器的使用分为俩个阶段:
1 )查询出一个学生对象
from students.models import Student
student = Student.objects.get(id=3)
2 ) 构造序列化器对象
from .serializers import StudentSerializer
serializer = StudentSerializer(instance=student)
3 )获取序列化的数据
通过data属性可以获取序列化后的数据
serializer.data
完整视图代码:
from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse
class StudentView(View):
"""使用序列化器序列化转换单个模型数据"""
def get(self,request,pk):
# 获取数据
student = Student.objects.get(pk=pk)
# 数据转换[序列化过程]
serializer = StudentSerializer(instance=student)
print(serializer.data)
# 响应数据
return JsonResponse(serializer.data)
4 )如果被序列化的是包含多条数据的查询集
QuerySet , 可以通过添加 many=True 参数补充说明
"""使用序列化器序列化转换多个模型数据"""
def get(self,request):
# 获取数据
student\_list = Student.objects.all()
# 转换数据\[序列化过程\]
# 如果转换多个模型对象数据,则需要加上many=True
serializer = StudentSerializer(instance=student\_list,many=True)
print( serializer.data ) # 序列化器转换后的数据
# 响应数据给客户端
# 返回的json数据,如果是列表,则需要声明safe=False
return JsonResponse(serializer.data,safe=False)
# 访问结果:
# \[OrderedDict(\[('id', 1), ('name', 'xiaoming'), ('age', 20), ('sex', True), ('description', '测试')\]), OrderedDict(\[('id', 2), ('name', 'xiaohui'), ('age', 22), ('sex', True), ('description', '后面来的测试')\]), OrderedDict(\[('id', 4), ('name', '小张'), ('age', 18), ('sex', True), ('description', '猴赛雷')\])\]
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20)
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
通过构造序列化器对象,并将要反序列化的数据传递给data 构造参数, 从而进行验证
from booktest.serializers import BookInfoSerializer
data = {'bpub_date': 123}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # 返回False
serializer.errors
serializer.validated_data # {}
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.errors # {}
serializer.validated_data # OrderedDict([('btitle', 'python')])
is_valid()方法还可以在验证失败时抛出异常
Serializer.ValidationError. 可以通过传递raise_exception=True参数开启吗REST framework接收到此异常, 会向前端返回HTTP400 BadRequest 响应.
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
如果觉得这些都不够需要再补充定义验证行为, 可以使用以下三种方法:
! ) validate_字段名
对
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
…
def validate\_btitle(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value
测试:
from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # False
serializer.errors
2 ) validate
在序列化器中需要同时对对多个字段进行比较验证时可以定义validate方法来验证,如
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
…
def validate(self, attrs):
bread = attrs\['bread'\]
bcomment = attrs\['bcomment'\]
if bread < bcomment:
raise serializers.ValidationError('阅读量小于评论量')
return attrs
测试:
from booktest.serializers import BookInfoSerializer
data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=data)
s.is_valid() # False
s.errors
3 ) validators
在字段中添加validators选项参数, 也可以补充验证行为, 如
def about_django(value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
测试:
from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # False
serializer.errors
前面的验证数据成功后.我们可以使用序列化器来完成数据反序列化的过程, 这个过程可以把数据传成模型类对象.
可以通过实现create( 和 update( 俩个方法来实现.
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
…
def create(self, validated\_data):
"""新建"""
return BookInfo(\*\*validated\_data)
def update(self, instance, validated\_data):
"""更新,instance为要更新的对象实例"""
instance.btitle = validated\_data.get('btitle', instance.btitle)
instance.bpub\_date = validated\_data.get('bpub\_date', instance.bpub\_date)
instance.bread = validated\_data.get('bread', instance.bread)
instance.bcomment = validated\_data.get('bcomment', instance.bcomment)
return instance
如果需要在返回数据对象的时候吗也将数据保存到数据库中吗则可以进行如下修改
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
…
def create(self, validated\_data):
"""新建"""
return BookInfo.objects.create(\*\*validated\_data)
def update(self, instance, validated\_data):
"""更新,instance为要更新的对象实例"""
instance.btitle = validated\_data.get('btitle', instance.btitle)
instance.bpub\_date = validated\_data.get('bpub\_date', instance.bpub\_date)
instance.bread = validated\_data.get('bread', instance.bread)
instance.bcomment = validated\_data.get('bcomment', instance.bcomment)
instance.save()
return instance
实行了上述俩个方法后, 在反序列化数据的时候, 就可以通过save() 方法返回一个数据对象实例化
book = serializer.save()
如果创建序列化器对象的时候, 没有传递instance实例, 则调用save( )方法的时候吗create( 被调用, 相反, 如果传递了instance实例, 则调用save() 方法的时候,update() 被调用.
from db.serializers import BookInfoSerializer
data = {'btitle': '封神演义'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.save() #
from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天剑'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid() # True
serializer.save() #
book.btitle # '倚天剑'
1 ) 在对序列化器进行save()保存时, 可以额为传递数据, 这些数据可以在create() 和update( 中的validated_date参数获取到
# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=request.user)
2 ) 默认序列化器必须传递所有热气red的字段, 否则会抛出验证异常. 但是我们可以使用partial参数来允许部分字段更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
1 ) 使用飞力达来明确字段, __all__ 表名包含所有字段, 也可以写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date')
2 ) 使用exclude可以明确排除哪些字段
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
exclude = ('image',)
3 )显示指明字段,如:
class HeroInfoSerializer(serializers.ModelSerializer):
hbook = BookInfoSerializer()
class Meta:
model = HeroInfo
fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
4 ) 指明只读字段
可以通过read_only_fields指明只读字段, 仅用于序列化输出的字段
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
read_only_fields = ('id', 'bread', 'bcomment')
可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选型参数
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
extra_kwargs = {
'bread': {'min_value': 0, 'required': True},
'bcomment': {'min_value': 0, 'required': True},
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章