Django-DRF-序列化模型实战(一)
前言:本文带领大家了解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),将数据转换成数据流,然后序列化验证后,保存到数据库中。