rest framework api

Django-DRF-序列化模型实战(一)

2018-07-31  本文已影响34人  程序员同行者

前言:本文带领大家了解django-rest-framework “序列化模型”的一些使用及知识点,通过实战演示进一步让大家能简单看懂,并且上手操作,了解DRF的强大。

一、App创建与管理

在讲解本文主题“序列化模型”之前,我们需要创建一个app来进行实际的演示,因此你想更深入的了解学习本文知识点的话,建议你跟着一起操作。

首先创建一个app:

$ python manage.py startapp idcs

随着项目越来越庞大,项目里的app越来越多,因此需要将所有app进行管理起来,管理方法如下

创建管理app的目录:

$ mkdir apps
$ mv idcs apps

需要知道的是,创建的app也是一个python的模块,我们后面也可以将一些非app的模块放到这里面,目的是便于管理。

因为目录结构有了变化,Django找不到创建的app了,所以需要我们配置一下,告诉Django在哪里能找到我们创建的app。方法如下
Django加载apps目录:

$ vim ops/settings.py

import os
import sys  # 先导入sys模块
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))  # 增加这一行

INSTALLED_APPS = [
······
    'idcs.apps.IdcsConfig',        #在apps列表里添加刚刚创建的idcs app
]

需要在Django的配置文件里加载它,这里使用sys模块将apps所在的路径插入到sys.path中,这样Django在寻找app的时候就知道去哪找了。

idcs创建urls.py文件
上面通过startapp创建好app后,你会发现app里没有urls.py文件。嘿嘿嘿,如果没有这个文件,你启动Django项目试试?它保证不会任性不出错(讽刺)。。。

因此,我们需要自己来创建这个文件,并写下urlpatterns字段。

$ vim apps/idcs/urls.py
urlpatterns = [
]

配置路由:
app的导入和url问题都搞定了,接下来需要在全局urls.py文件里配置idcs这个app的路由关系

$ vim ops/urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^idcs/', include("idcs.urls")),     # 默认无法识别,Pycharm工具配置自动识别方法:右击“apps”目录 -->Mark -->Source Root 
]

安装DRF:

配置好app后,我们顺便把DRF也安装和配置一下,非常简单快速。

1、安装

$ pip install django-rest-framework

2、配置Django加载DRF

Django使用drf比较简单,直接在apps列表里写入如下模块即可完成,后面就等着使用了。

$ vim ops/settings.py

INSTALLED_APPS = [
······
    'rest_framework',
]

好,完事。

二、序列化模型

2.1、同步Idc模型

在models模型文件里创建字段如下,并使用下面给出的命令快速同步到数据库中

$ vim idcs/models.py

class Idc(models.Model):
    name    = models.CharField("机房名称",max_length=32)
    address = models.CharField("机房地址",max_length=256)
    phone  = models.CharField("联系人",max_length=15)
    email  = models.EmailField("邮件地址",default="null")
    letter  = models.CharField("IDC简称",max_length=5)

    def __str__(self):
        return self.name
    class Meta:
        db_table = 'resource_idc'

$ python manage.py showmigrations
$ python manage.py migrate
$ python manage.py makemigrations idcs
$ python manage.py migrate idcs

2.2、定义序列化类

在idc app目录下新建一个文件serializers.py,因为是做序列化,而序列化是针对模型的,所以需要跟模型文件models.py在同一个目录下

$ vim idcs/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) # 字段必须传, 最大限制32个字符
    address = serializers.CharField(required=True, max_length=256)
    phone  = serializers.CharField(required=True, max_length=15)
    email  = serializers.CharField(required=True)
    letter  = serializers.CharField(required=True, max_length=5)

2.3、使用序列化

通过python mamage.py shell往IDC模型里添加两条记录

In [1]: from idcs.models import Idc
In [2]: idc = Idc()
In [3]: idc.name = '亦庄机房'
In [4]: idc.address = '北京亦庄机房'
In [5]: idc.phone = '12312341234'
In [6]: idc.email = 'nick@qq.com'
In [7]: idc.letter = 'yz'
In [8]: idc.save()
In [9]:
In [9]: idc.id = None
In [10]: idc.name = '兆维机房'
In [11]: idc.address = '兆维工业园'
In [12]: idc.phone = '18512341234'
In [13]: idc.email = 'zw@qq.com'
In [14]: idc.letter = 'zw'
In [15]: idc.save()

2.3.1、正向序列化

正向序列化的定义:从“数据库”里获取数据并序列化后返回标准JSON类型的数据给前端

具体使用序列化的操作如下:

In [17]: from idcs.serializers import IdcSerializer # 导入序列化类

In [18]: idc = Idc.objects.get(pk=1)  # 获取一条IDC信息,等待序列化

In [19]: idc
Out[19]: <Idc: 亦庄机房>

In [20]: serializers = IdcSerializer(idc)  # 将idc对象传给序列化类 进行序列化操作后存放到一个变量里,序列化完成。

In [21]: serializers # 输出结果,会把序列化里的字段给打印出来
Out[21]:
IdcSerializer(<Idc: 亦庄机房>):
    id = IntegerField()
    name = CharField()
    address = CharField()
    phone = CharField()
    email = CharField()
    letter = CharField()

In [23]: serializers.data # 通过.data能获取到所有的数据
Out[23]: {'id': 1, 'name': '亦庄机房', 'address': '北京亦庄机房', 'phone': '12312341234', 'email': 'nick@qq.com', 'letter': 'yz'}

In [24]: a = serializers.data

In [25]: type(a)
Out[25]: rest_framework.utils.serializer_helpers.ReturnDict

能看到serializers.data的类型是一个ReturnDict,而我们最终需求是需要转换成Json类型返回给前端的,那如何转换呢?

使用drf内置模块将结果转换成标准的json数据:

In [26]: from rest_framework.renderers import JSONRenderer

In [27]: ?JSONRenderer
Init signature: JSONRenderer()
Docstring:      Renderer which serializes to JSON.
File:          ~/Projects/Python/v3/VirtualSource/venv/lib/python3.6/site-packages/rest_framework/renderers.py
Type:          type

In [28]: jr = JSONRenderer() # 实例化

In [29]: jr.render(serializers.data) # 使用render方法将结果转换成标准的Json数据
Out[29]: b'{"id":1,"name":"\xe4\xba\xa6\xe5\xba\x84\xe6\x9c\xba\xe6\x88\xbf","address":"\xe5\x8c\x97\xe4\xba\xac\xe4\xba\xa6\xe5\xba\x84\xe6\x9c\xba\xe6\x88\xbf","phone":"12312341234","email":"nick@qq.com","letter":"yz"}'

In [30]: content = jr.render(serializers.data)  # 拿到这个数据,就可以直接返回给前端了。

正向序列化多条记录

In [1]: from idcs.models import  Idc

In [2]: from idcs.serializers import IdcSerializer

In [3]: Idc.objects.all()
Out[3]: <QuerySet [<Idc: 亦庄机房>, <Idc: 兆维机房>]>

In [4]: data = IdcSerializer(Idc.objects.all(), many=True)  # 关键在于这一步,使用many=True声明传入的是多个object对象

In [5]: data
Out[15]: 
IdcSerializer(<QuerySet [<Idc: 亦庄机房>, <Idc: 兆维机房>]>, many=True):
    id = IntegerField()
    name = CharField()
    address = CharField()
    phone = CharField()
    email = CharField()
    letter = CharField()

In [6]: from rest_framework.renderers import  JSONRenderer

In [6]: content = JSONRenderer().render(data.data)

In [7]: content
Out[7]: 
b'[{"id":1,"name":"\xe4\xba\xa6\xe5\xba\x84\xe6\x9c\xba\xe6\x88\xbf","address":"\xe5\x8c\x97\xe4\xba\xac\xe4\xba\xa6\xe5\xba\x84\xe6\x9c\xba\xe6\x88\xbf","phone":"12312341234","email":"nick@qq.com","letter":"yz"},{"id":2,"name":"\xe5\x85\x86\xe7\xbb\xb4\xe6\x9c\xba\xe6\x88\xbf","address":"\xe5\x85\x86\xe7\xbb\xb4\xe5\xb7\xa5\xe4\xb8\x9a\xe5\x9b\xad","phone":"18512341234","email":"zw@qq.com","letter":"zw"}]'

小结:

序列化的过程如下

1. mysql获取数据

2. queryset = Idc.objects.all() #获取单个或所有idc对象

3. content = JSORNRenderer().render(queryset) # 转换成标准Json数据

4. HttpResponse(content) # 返回给前端

重点:
上面的小结里,能看到序列化的过程,那序列化还能做些什么事情呢?它可以验证前端传入过来的数据,并且添加、更新这些数据

2.3.2、反向序列化
反向序列化的定义从“前端接口”接收添加的数据并序列化后返回一个object对象给后端,而且可以进行数据验证以及添加到数据库的操作。

编写序列化验证、创建、更新、保存规则:

$ vim idcs/serializers.py

from rest_framework import serializers
from .models import Idc  # 需要导入Idc模型

class IdcSerializer(serializers.Serializer):
    """
    Idc, 序列化类
    """
    id      = serializers.IntegerField(read_only=True) # 处理只读
    name    = serializers.CharField(required=True, max_length=32) # 字段必须传, 最大限制32个字符
    address = serializers.CharField(required=True, max_length=256)
    phone  = serializers.CharField(required=True, max_length=15)
    email  = serializers.CharField(required=True)
    letter  = serializers.CharField(required=True, max_length=5)


    def create(self, validated_data):
        return Idc.objects.create(**validated_data)  # 调用Idc模型进行create操作

    def update(self, instance, validated_data): # 参数介绍:instance是当前的对象,validated_data是处理过的干净数据
        '''
        update方法可以允许修改什么字段,如果有不需要修改的字段,不写即可
        '''
        instance.name      = validated_data.get("name",instance.name)
        instance.address    = validated_data.get("address",instance.name)
        instance.phone      = validated_data.get("phone",instance.name)
        instance.email      = validated_data.get("email",instance.name)
        instance.save()
        return instance

注意:在“正向序列化”的时候,CharField字段里的参数都没有作用,只有在“反向序列化”是才会有作用。

反向序列化的操作过程:

In [1]: from idcs.serializers import IdcSerializer

In [2]: data = {'id': 1,'name': '数北机房','address': '北京数北机房','phone': '12312341234','email': 'aaa@123.com','letter': 'yz'}In [2]: data = {'id': 1,
  ...:  'name': '亦庄机房',
  ...:  'address': '北京亦庄机房',
  ...:  'phone': '12345678',
  ...:  'email': 'aaa@123.com',
  ...:  'letter': 'yz'}   # 这里的data数据模拟前端接口传进来的数据哈

In [3]: serializer = IdcSerializer(data=data) # 将Json格式的数据传入IdcSerializer进行序列化

In [4]: serializer # 得到序列化后的结果
Out[4]: 
IdcSerializer(data={'id': 1, 'name': '亦庄机房', 'address': '北京亦庄机房', 'phone': '12345678', 'email': 'rock@51reboot.com', 'letter': 'yz'}):
    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()  # 查看验证是否通过,调用的是(required=True, max_length=32)这些条件参数哈
Out[5]: True

In [6]: serializer.validated_data # 通过validated_data获取数据
Out[6]: 
OrderedDict([('name', '亦庄机房'),
            ('address', '北京亦庄机房'),
            ('phone', '12345678'),
            ('email', 'aaa@123.com'),
            ('letter', 'yz')])

In [7]: del data["id"]  # 删除id数据后方便添加到数据库中

In [8]: data
Out[8]: 
{'name': '亦庄机房',
'address': '北京亦庄机房',
'phone': '12345678',
'email': 'aaa@123.com',
'letter': 'yz'}

In [9]: serializer = IdcSerializer(data=data) # 重新执行验证

In [10]: serializer.is_valid()
Out[10]: True

In [11]: serializer.save()  # 这里的save调用了IdcSerializer类里我们写的create方法
Out[11]: <Idc: 亦庄机房>

上面在编写IdcSerializer序列化类的时候,写了create和update方法,那么这两个方法有什么用呢?又是如何使用的呢?

重点概念Django能自动判断你提交的请求是需要增加,判断的标准是基于ID,如果传入的数据里有ID的话,那么认为你是需要进行修改,没有ID则认为是需要进行创建

在上面操作细节中,在执行serializer.save() 方法时,事实上是调用了IdcSerializer类的create方法,就是基于Django智能判断来实现的。

2.4、序列化总结

1、正向序列化

1. 拿到quertset
2. 将quertset给序列化类
    serializer = IdcSerializer(idc)
    serializer = IdcSerializer(Idc.objects.all(), many=True)
3. 转JSON
    JSONRenderer().render(serializer.data)

2、反向序列化

data = JSONRenderer().parse(content)
serializer = IdcSerializer(data=data)
serializer.is_valid()
serializer.save()

正向序列化:从数据库里拿出来数据,然后返回Json给前端

反向序列化:从前端接口拿到数据(data),将数据转换成数据流,然后序列化验证后,保存到数据库中。

上一篇下一篇

猜你喜欢

热点阅读