一.前后端分离及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 = "1234568"                                      
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': '1234568', '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":"xe6x98x86xe6x98x8exe6x9cxbaxe6x88xbf","address":"xe6x98x86xe6x98x8e","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': '1234568',
 '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': '1234568', 
   ...:     'email': 'rock@51reboot.com', 
   ...:      'letter': 'km'}                                       

In [3]: serializer = IdcSerializer(data=data)        反序列化 后如下中可看到有验证规则了             

In [4]: serializer                                                 
Out[4]: 
IdcSerializer(data={'id': 1, 'name': '昆明机房', 'address': '昆明', 'phone': '1234568', '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', '1234568'),
             ('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': '1234568', 
   ...:     '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":"xe6x98x86xe6x98x8exe6x9cxbaxe6x88xbf","address":"xe6x98x86xe6x98x8e","phone":"1234568","email":"rock@51reboot.com","letter":"km"},{"id":2,"name":"xe5xa4xa7xe7x90x86xe6x9cxbaxe6x88xbf","address":"xe5xa4xa7xe7x90x86","phone":"1234568","email":"rock@51reboot.com","letter":"dl"},{"id":3,"name":"xe6x98x86xe6x98x8exe6x9cxbaxe6x88xbf","address":"xe6x98x86xe6x98x8e","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 #返回
原文地址:https://www.cnblogs.com/dbslinux/p/13049696.html