zoukankan      html  css  js  c++  java
  • 一.前后端分离及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 #返回
  • 相关阅读:
    XSD文件生成C#VO实体类
    WPF根据Oracle数据库的表,生成CS文件小工具
    【求助】WPF 在XP下 有的Textbox光标会消失
    【转】oracle中in和exists的区别
    Spire.DOC生成表格测试
    【转】C#调用Windows图片和传真查看器打开图片
    WPF MVVM下做发送短信小按钮
    SignalR Progress
    C# readonly
    Settings.settings
  • 原文地址:https://www.cnblogs.com/dbslinux/p/13049696.html
Copyright © 2011-2022 走看看