一.前后端分离及drf实现序列化的原理
为什么要进行前后端分离
- 可pc、app、pad多端适应
- SPA开发模式的流行--单页web应用(只有一html页面)
- 可实现前后端开发职责清(不分离时,前端是通过后端给的变量并渲染出来方式拿到数据!!后端是通过前端准备好的模版,并替换其中变量方式传数据)
- 不分时开发效率问题,前后端相互等待
- 不分时前端一直配合着后端,能力受限制
- 不分时后端开发语言和模板高度耦合,导致开发语言依赖严重--现在可把语言和模板分离开
前后端分离缺点
- 前后端学习门槛增加
- 数据依赖导致文档重要性增加
- 前端工作量加大
- SEO难度加大
- 后端开发迁移成本增加
restfull api目前是前后端分离的最佳实践
- 轻量的,直接通过http方式进行数据交互,不需要额外的协议,支持post/get/put/delete操作
- 面向资源,一面了然,具有自解释性
- 数据描述简单,一般是通过json或者xml做数据通信(后端准备好数据以json形式返回给前端,前端拿到的就是直接可用的对象)
理解RESTful架构:概念参考http://www.ruanyifeng.com/blog/2011/09/restful.html
实战参考http://www.ruanyifeng.com/blog/2014/05/restful_api.html
二.开始drf
1.项目准备
开始项目:
(python36env) [vagrant@CentOS7 devops]$ python manage.py startapp idcs
新建项目目录下apps包用于放将来很多的app--idcs也放其中。
(1)urls.py:--注意为了让其能识别idcs/urls有两方式:
从pycharm上识别:点击apps包右键--mark as--source root(意思是以apps目录为查找模块的目录)
从代码层面识别:把apps目录加到全局path路径BASE_DIR中,
import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,os.path.join(BASE_DIR, "apps"))
--sys.path中存着django所有可搜索加载的目录,并插到最开始的地方所以用insert(0)。并加在django项目下。
激活app:
INSTALLED_APPS = [
.......
'idcs'
]
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^idcs', include("idcs.urls")),
]
(2)idcs/urls.py: 定义一空变量即可
from django.conf.urls import include, url
urlpatterns = [ ]
2.drf安装及配置:
(python36env) [vagrant@CentOS7 devops]$ pip install djangorestframework
INSTALLED_APPS = (
......
'rest_framework'
)
然后重启pycharm重新同步远程环境。
3.序列化模型
(1)准备模型models.py:
from django.db import models class Idc(models.Model):
name = models.CharField("机房名",max_length=32)
address = models.CharField("机房地址",max_length=200)
phone = models.CharField("机房联系电话",max_length=15)
email = models.EmailField("机房联系email")
letter = models.CharField("idc字母简称",max_length=5)
def __str__(self):
return self.name
class Meta:
db_table = 'resources_idc'
同步数据:
(python36env) [vagrant@CentOS7 devops]$ python manage.py makemigrations idcs
(python36env) [vagrant@CentOS7 devops]$ python manage.py migrate idcs
(2)序列化模型:在idcs下新建serializers.py
from rest_framework import serializers class IdcSerializer(serializers.Serializer):
"""
Idc 序列化类
"""
id = serializers.IntegerField()
name = serializers.CharField()
address = serializers.CharField()
phone = serializers.CharField()
email = serializers.EmailField()
letter = serializers.CharField()
a.把模型中的所有字段和id字段都拿过来--定义它的变量类型(根据模型的字段类型定义序列化--是为了返回给前端什么样的字段/数据类型)
b.使用序列化
为了测试,所以先手动往库中添加点记录(添加到idc模型中)。
(python36env) [vagrant@CentOS7 devops]$ python manage.py shell
In [1]: from idcs.models import Idc
In [2]: idc = Idc()
In [3]: idc.name = "昆明机房"
In [4]: idc.address = "昆明"
In [5]: idc.phone = ""
In [6]: idc.email = "rock@51reboot.com"
In [7]: idc.letter = "km"
In [8]: idc.save()
In [9]: idc.id = None
In [10]: idc.name = "大理机房"
In [11]: idc.address = "大理"
In [12]: idc.letter = "dl"
In [13]: idc.save()
In [14]: Idc.objects.all() 查询如下有两条记录了
Out[14]: <QuerySet [<Idc: 昆明机房>, <Idc: 大理机房>]>
先导入idc序列化类,并准备一条记录,然后序列化类(要实例化类--把记录传给它)并保存在一变量中,
把此实例化后的对象用data属性一打印出来就直接是json格式的数据了:
In [16]: from idcs.serializers import IdcSerializer
In [17]: idc = Idc.objects.get(pk=1)
In [18]: idc
Out[18]: <Idc: 昆明机房>
In [19]: serializer = IdcSerializer(idc)
In [20]: serializer
Out[20]:
IdcSerializer(<Idc: 昆明机房>):
id = IntegerField()
name = CharField()
address = CharField()
phone = CharField()
email = EmailField()
letter = CharField()
In [21]: serializer.data
Out[21]: {'id': 1, 'name': '昆明机房', 'address': '昆明', 'phone': '', 'email': 'rock@51reboot.com', 'letter': 'km'}
In [22]: a = serializer.data
In [23]: type(a)
Out[23]: rest_framework.utils.serializer_helpers.ReturnDict
但它是rest字典类型的数据,所以要给它转成json,且用rest提供的方法转(不能用json.dumps):
先实例化JSONRenderer方法,并给它传一数据----如下结果中,这才是标准的返回给前端的数据
In [25]: from rest_framework.renderers import JSONRenderer
In [26]: jr = JSONRenderer()
In [27]: jr.render(serializer.data)
Out[27]: b'{"id":1,"name":"\xe6\x98\x86\xe6\x98\x8e\xe6\x9c\xba\xe6\x88\xbf","address":"\xe6\x98\x86\xe6\x98\x8e","phone":"1234568","email":"rock@51reboot.com","letter":"km"}'
In [28]: content = jr.render(serializer.data) 保存到一变量中,就可直接通过httpresponse对象直接返回给前端
c.用序列化做字段的简单验证serializers.py:
from rest_framework import serializers
class IdcSerializer(serializers.Serializer):
"""
Idc 序列化类
"""
id = serializers.IntegerField(read_only=True) #只读的,即忽略可不传
name = serializers.CharField(required=True,max_length=32) #意思是提交数据时此字段必须填且不能为空
address = serializers.CharField(required=True,max_length=256)
phone = serializers.CharField(required=True,max_length=15)
email = serializers.EmailField(required=True)
letter = serializers.CharField(required=True,max_length=5)
d.怎样把前端提交过来的数据content插入到数据库中---反序列化(即把bytes类型转成模型对象)
首先它是一byte类型,是一种流
In [31]: from django.utils.six import BytesIO
In [32]: stream = BytesIO(content)
In [33]: stream
Out[33]: <_io.BytesIO at 0x7fe29ac4b410>
In [35]: from rest_framework.parsers import JSONParser 后可看到如下中是标准的json了
In [36]: data = JSONParser().parse(stream)
In [37]: data
Out[37]:
{'id': 1,
'name': '昆明机房',
'address': '昆明',
'phone': '',
'email': 'rock@51reboot.com',
'letter': 'km'}
In [38]: serializer = IdcSerializer(data=data) 反序列化后如下就生成标准的原始数据了
In [39]: serializer
IdcSerializer(data={'id': 1, 'name': '昆明机房', 'address': '昆明', 'phone': '1234568', 'email': 'rock@51reboot.com', 'letter': 'km'}):
id = IntegerField()
name = CharField()
address = CharField()
phone = CharField()
email = EmailField()
letter = CharField()
但是可以看到上述所有字段中都没有规则,所以得让其重新生效一次--要重新加载IdcSerializer类(因为这个类我已经修改过了,加了验证规则),而上述拿到的序列类它是没有验证规则
先退出django shell,再重新进入
In [1]: from idcs.serializers import IdcSerializer
In [2]: data = {'id': 1, 这是前端传过来的数据
...: 'name': '昆明机房',
...: 'address': '昆明',
...: 'phone': '',
...: 'email': 'rock@51reboot.com',
...: 'letter': 'km'} In [3]: serializer = IdcSerializer(data=data) 反序列化 后如下中可看到有验证规则了 In [4]: serializer
Out[4]:
IdcSerializer(data={'id': 1, 'name': '昆明机房', 'address': '昆明', 'phone': '', 'email': 'rock@51reboot.com', 'letter': 'km'}):
id = IntegerField(read_only=True)
name = CharField(max_length=32, required=True)
address = CharField(max_length=256, required=True)
phone = CharField(max_length=15, required=True)
email = EmailField(required=True)
letter = CharField(max_length=5, required=True)
In [5]: serializer.is_valid() 进行验证
Out[5]: True
e.此时数据已准备好,验证规则也有了,也验证完了,此时我需要拿到干净的数据(不等于前端传过来的数据)
In [6]: serializer.validated_data 此时就拿到了干净的数据
Out[6]:
OrderedDict([('name', '昆明机房'),
('address', '昆明'),
('phone', ''),
('email', 'rock@51reboot.com'),
('letter', 'km')])
f.拿到干净的数据后要想保存得重写create方法,并把已经验证过的数据给它再返回
serializer.py中加入如下代码:
from rest_framework import serializers
from .models import Idc
class .....
def create(self, validated_data):
return Idc.objects.create(**validated_data)
退出django shell再进入并再把前端传的数据拿过来且把id去掉,就表示新建(没有传id django认为是创建数据,有传id表示认为修改数据),--因为有save方法时它会自动判断你是调用create还是update方法
所以对数据进行序列化--验证---保存,如下所示一条记录就保存了且做了验证
In [2]: from idcs.serializers import IdcSerializer
In [3]: data = {'id': 1,
...: 'name': '昆明机房',
...: 'address': '昆明',
...: 'phone': '',
...: 'email': 'rock@51reboot.com',
...: 'letter': 'km'}
In [4]: del data["id"]
In [5]: serializer = IdcSerializer(data=data)
In [6]: serializer.is_valid()
Out[6]: True
In [7]: serializer.save()
Out[7]: <Idc: 昆明机房>
In [8]: from idcs.models import Idc 测试有无验证成功,如下有三条记录说明成功了
In [9]: Idc.objects.all()
Out[9]: <QuerySet [<Idc: 昆明机房>, <Idc: 大理机房>, <Idc: 昆明机房>]>
g.我上述所有操作都是只序列化一条记录,那如何序列化多条记录
给它传一queryset即可(Idc.objects.all(), many=True)表示有多条。
In [11]: data = IdcSerializer(Idc.objects.all(), many=True) In [12]: data
Out[12]:
IdcSerializer(<QuerySet [<Idc: 昆明机房>, <Idc: 大理机房>, <Idc: 昆明机房>]>, many=True):
id = IntegerField(read_only=True)
name = CharField(max_length=32, required=True)
address = CharField(max_length=256, required=True)
phone = CharField(max_length=15, required=True)
email = EmailField(required=True)
letter = CharField(max_length=5, required=True) 那如何拿到数据?--通过JSONRenderer,并传给它上述的data数据,且它是序列化类所以用data属性,最终如下它就是一多标准数据的列表了
In [14]: from rest_framework.renderers import JSONRenderer
In [15]: content = JSONRenderer().render(data.data)
In [16]: content
Out[16]: b'[{"id":1,"name":"\xe6\x98\x86\xe6\x98\x8e\xe6\x9c\xba\xe6\x88\xbf","address":"\xe6\x98\x86\xe6\x98\x8e","phone":"1234568","email":"rock@51reboot.com","letter":"km"},{"id":2,"name":"\xe5\xa4\xa7\xe7\x90\x86\xe6\x9c\xba\xe6\x88\xbf","address":"\xe5\xa4\xa7\xe7\x90\x86","phone":"1234568","email":"rock@51reboot.com","letter":"dl"},{"id":3,"name":"\xe6\x98\x86\xe6\x98\x8e\xe6\x9c\xba\xe6\x88\xbf","address":"\xe6\x98\x86\xe6\x98\x8e","phone":"1234568","email":"rock@51reboot.com","letter":"km"}]'
扩展:update方法
class.....
def create(self, validated_data):
return Idc.objects.create(**validated_data)
def update(self, instance, validated_data): #对已经验证过的非常干净的数据进行修改,instance是当前的对象
instance.name = validated_data.get("name", instance.name) #哪些字段可以修改,且默认名是
instance.address = validated_data.get("address", instance.address)
instance.phone = validated_data.get("phone", instance.phone)
instance.email = validated_data.get("email", instance.email)
instance.save() #保存
return instance #返回
一.前后端分离及drf实现序列化的原理的更多相关文章
- 前后端分离之DRF——1
1. 作用 1. 序列化,序列化器会把模型对象转成字典,经过 response 以后变成 json 字符串 2. 反序列化,把客户端发送过来的数据,经过 request 以后变成字典,序列化器可以把字 ...
- 前后端分离djangorestframework——序列化与反序列化数据
我们写好后端的代码,要把数据交给前端的展示的,这个数据以什么类型给前端呢?学到这里,我们已经知道这个数据最好是json字符串才行,因为网络间的传输,只认字符串或者二进制,字符串就是我们的数据,二进制就 ...
- python drf+xadmin+react+dva+react-native+sentry+nginx 搭建前后端分离的博客完整平台
前言: 经过差不多半年的开发,搭建从前端到服务器,实现了前后端分离的一个集PC端.移动端的多端应用,实属不易,今天得空,好好写篇文章,记录这些天的成果.同时也做个分享. 演示网站地址: http:// ...
- 前后端分离djangorestframework——分页组件
Pagination 为什么要分页也不用多说了,大家都懂,DRF也自带了分页组件 这次用 前后端分离djangorestframework——序列化与反序列化数据 文章里用到的数据,数据库用的my ...
- 前后端分离djangorestframework——视图组件
CBV与FBV CBV之前说过就是在view.py里写视图类,在序列化时用过,FBV就是常用的视图函数,两者的功能都可以实现功能,但是在restful规范方面的话,CBV更方便,FBV还要用reque ...
- 前后端分离和restful开发规范
一.web开发的两种模式 1.前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高. 这种应用模式比 ...
- 【转】从MVC到前后端分离
1. 理解MVC MVC是一种经典的设计模式,全名为Model-View-Controller,即模型-视图-控制器. 其中,模型是用于封装数据的载体,例如,在Java中一般通过一个简单的POJO(P ...
- 从MVC到前后端分离
摘要:MVC模式早在上个世纪70年代就诞生了,直到今天它依然存在,可见生命力相当之强.MVC模式最早用于Smalltalk语言中,最后在其它许多开发语言中都得到了很好的应用,例如,Java中的Stru ...
- dotnetcore vue+elementUI 前后端分离架二(后端篇)
前言 最近几年前后端分离架构大行其道,而且各种框架也是层出不穷.本文通过dotnetcore +vue 来介绍 前后端分离架构实战. 涉及的技术栈 服务端技术 mysql 本项目使用mysql 作为持 ...
随机推荐
- Java实现 LeetCode 768 最多能完成排序的块 II(左右便利)
768. 最多能完成排序的块 II 这个问题和"最多能完成排序的块"相似,但给定数组中的元素可以重复,输入数组最大长度为2000,其中的元素最大为10**8. arr是一个可能包含 ...
- Java实现 LeetCode 645 错误的集合(暴力)
645. 错误的集合 集合 S 包含从1到 n 的整数.不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复. 给定一个数组 n ...
- CSDN怎么跳转到指定的位置
位置1 只需要给上面的链接和下面的id一致即可 位置1
- Java实现蓝桥杯VIP 算法训练 sign函数
问题描述 给定实数x,输出sign(x)的值. sign(x)是符号函数,如果x>0,则返回1:如果x=0,则返回0:如果x<0,则返回-1. 输入格式 一行一个实数x. 输出格式 一行一 ...
- Java实现 LeetCode 373 查找和最小的K对数字
373. 查找和最小的K对数字 给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k. 定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2. 找 ...
- Java实现 LeetCode 171 Excel表列序号
171. Excel表列序号 给定一个Excel表格中的列名称,返回其相应的列序号. 例如, A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> ...
- Java实现蓝桥杯二项式的系数规律
二项式的系数规律,我国数学家很早就发现了. 如[图1.png],我国南宋数学家杨辉1261年所著的<详解九章算法>一书里就出现了. 其排列规律: 1 1 1 2 1 3 3 1 4 6 4 ...
- Java实现台阶问题
1 问题描述 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级,求总共有多少种跳法. 2 解决方案 2.1 递归法 如果整个台阶只有1级,则显然只有一种跳法.如果台阶有2级,则有两种跳法:一种是分 ...
- java实现第四届蓝桥杯颠倒的价牌
颠倒的价牌 题目描述 小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店. 其标价都是4位数字(即千元不等). 小李为了标价清晰.方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就 ...
- BFART算法
参考:https://zhuanlan.zhihu.com/p/31498036 https://www.jianshu.com/p/83bb10ad1d32