前言:本文帶領(lǐng)大家了解django-rest-framework “序列化模型”的一些使用及知識點芹橡,通過實戰(zhàn)演示進一步讓大家能簡單看懂,并且上手操作磺樱,了解DRF的強大誓竿。
一磅网、App創(chuàng)建與管理
在講解本文主題“序列化模型”之前,我們需要創(chuàng)建一個app來進行實際的演示烤黍,因此你想更深入的了解學(xué)習(xí)本文知識點的話知市,建議你跟著一起操作傻盟。
首先創(chuàng)建一個app:
$ python manage.py startapp idcs
隨著項目越來越龐大,項目里的app越來越多嫂丙,因此需要將所有app進行管理起來娘赴,管理方法如下
創(chuàng)建管理app的目錄:
$ mkdir apps
$ mv idcs apps
需要知道的是,創(chuàng)建的app也是一個python的模塊跟啤,我們后面也可以將一些非app的模塊放到這里面诽表,目的是便于管理。
因為目錄結(jié)構(gòu)有了變化隅肥,Django找不到創(chuàng)建的app了竿奏,所以需要我們配置一下,告訴Django在哪里能找到我們創(chuàng)建的app腥放。方法如下
Django加載apps目錄:
$ vim ops/settings.py
import os
import sys # 先導(dǎo)入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列表里添加剛剛創(chuàng)建的idcs app
]
需要在Django的配置文件里加載它泛啸,這里使用sys模塊將apps所在的路徑插入到sys.path中,這樣Django在尋找app的時候就知道去哪找了秃症。
idcs創(chuàng)建urls.py文件:
上面通過startapp創(chuàng)建好app后候址,你會發(fā)現(xiàn)app里沒有urls.py文件。嘿嘿嘿种柑,如果沒有這個文件岗仑,你啟動Django項目試試?它保證不會任性不出錯(諷刺)聚请。荠雕。。
因此驶赏,我們需要自己來創(chuàng)建這個文件炸卑,并寫下urlpatterns字段。
$ vim apps/idcs/urls.py
urlpatterns = [
]
配置路由:
app的導(dǎo)入和url問題都搞定了母市,接下來需要在全局urls.py文件里配置idcs這個app的路由關(guān)系
$ 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模型文件里創(chuàng)建字段如下,并使用下面給出的命令快速同步到數(shù)據(jù)庫中
$ vim idcs/models.py
class Idc(models.Model):
name = models.CharField("機房名稱",max_length=32)
address = models.CharField("機房地址",max_length=256)
phone = models.CharField("聯(lián)系人",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 # 導(dǎo)入這個模塊旋讹,來使用序列化
# 定義并編寫序列化類
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 = '兆維工業(yè)園'
In [12]: idc.phone = '18512341234'
In [13]: idc.email = 'zw@qq.com'
In [14]: idc.letter = 'zw'
In [15]: idc.save()
2.3.1轿衔、正向序列化
正向序列化的定義:從“數(shù)據(jù)庫”里獲取數(shù)據(jù)并序列化后返回標準JSON類型的數(shù)據(jù)給前端
具體使用序列化的操作如下:
In [17]: from idcs.serializers import IdcSerializer # 導(dǎo)入序列化類
In [18]: idc = Idc.objects.get(pk=1) # 獲取一條IDC信息沉迹,等待序列化
In [19]: idc
Out[19]: <Idc: 亦莊機房>
In [20]: serializers = IdcSerializer(idc) # 將idc對象傳給序列化類 進行序列化操作后存放到一個變量里,序列化完成害驹。
In [21]: serializers # 輸出結(jié)果鞭呕,會把序列化里的字段給打印出來
Out[21]:
IdcSerializer(<Idc: 亦莊機房>):
id = IntegerField()
name = CharField()
address = CharField()
phone = CharField()
email = CharField()
letter = CharField()
In [23]: serializers.data # 通過.data能獲取到所有的數(shù)據(jù)
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
,而我們最終需求是需要轉(zhuǎn)換成Json類型返回給前端的宛官,那如何轉(zhuǎn)換呢琅拌?
使用drf內(nèi)置模塊將結(jié)果轉(zhuǎn)換成標準的json數(shù)據(jù):
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方法將結(jié)果轉(zhuǎn)換成標準的Json數(shù)據(jù)
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) # 拿到這個數(shù)據(jù),就可以直接返回給前端了摘刑。
正向序列化多條記錄
:
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) # 關(guān)鍵在于這一步进宝,使用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"}]'
小結(jié):
序列化的過程如下
1. mysql獲取數(shù)據(jù)
2. queryset = Idc.objects.all() #獲取單個或所有idc對象
3. content = JSORNRenderer().render(queryset) # 轉(zhuǎn)換成標準Json數(shù)據(jù)
4. HttpResponse(content) # 返回給前端
重點:
上面的小結(jié)里,能看到序列化的過程枷恕,那序列化還能做些什么事情呢党晋?它可以驗證前端傳入過來的數(shù)據(jù),并且添加徐块、更新這些數(shù)據(jù)
未玻。
2.3.2、反向序列化
反向序列化的定義:從“前端接口”接收添加的數(shù)據(jù)并序列化后返回一個object對象給后端
胡控,而且可以進行數(shù)據(jù)驗證以及添加到數(shù)據(jù)庫的操作扳剿。
編寫序列化驗證、創(chuàng)建昼激、更新庇绽、保存規(guī)則:
$ vim idcs/serializers.py
from rest_framework import serializers
from .models import Idc # 需要導(dǎo)入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) # 調(diào)用Idc模型進行create操作
def update(self, instance, validated_data): # 參數(shù)介紹:instance是當前的對象,validated_data是處理過的干凈數(shù)據(jù)
'''
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字段里的參數(shù)都沒有作用凡傅,只有在“反向序列化”是才會有作用辟狈。
反向序列化的操作過程:
In [1]: from idcs.serializers import IdcSerializer
In [2]: data = {'id': 1,'name': '數(shù)北機房','address': '北京數(shù)北機房','phone': '12312341234','email': 'aaa@123.com','letter': 'yz'}In [2]: data = {'id': 1,
...: 'name': '亦莊機房',
...: 'address': '北京亦莊機房',
...: 'phone': '12345678',
...: 'email': 'aaa@123.com',
...: 'letter': 'yz'} # 這里的data數(shù)據(jù)模擬前端接口傳進來的數(shù)據(jù)哈
In [3]: serializer = IdcSerializer(data=data) # 將Json格式的數(shù)據(jù)傳入IdcSerializer進行序列化
In [4]: serializer # 得到序列化后的結(jié)果
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() # 查看驗證是否通過,調(diào)用的是(required=True, max_length=32)這些條件參數(shù)哈
Out[5]: True
In [6]: serializer.validated_data # 通過validated_data獲取數(shù)據(jù)
Out[6]:
OrderedDict([('name', '亦莊機房'),
('address', '北京亦莊機房'),
('phone', '12345678'),
('email', 'aaa@123.com'),
('letter', 'yz')])
In [7]: del data["id"] # 刪除id數(shù)據(jù)后方便添加到數(shù)據(jù)庫中
In [8]: data
Out[8]:
{'name': '亦莊機房',
'address': '北京亦莊機房',
'phone': '12345678',
'email': 'aaa@123.com',
'letter': 'yz'}
In [9]: serializer = IdcSerializer(data=data) # 重新執(zhí)行驗證
In [10]: serializer.is_valid()
Out[10]: True
In [11]: serializer.save() # 這里的save調(diào)用了IdcSerializer類里我們寫的create方法
Out[11]: <Idc: 亦莊機房>
上面在編寫IdcSerializer序列化類的時候,寫了create和update方法哼转,那么這兩個方法有什么用呢明未?又是如何使用的呢?
重點概念:Django能自動判斷你提交的請求是需要增加壹蔓,判斷的標準是基于ID亚隅,如果傳入的數(shù)據(jù)里有ID的話,那么認為你是需要進行修改庶溶,沒有ID則認為是需要進行創(chuàng)建
在上面操作細節(jié)中煮纵,在執(zhí)行serializer.save() 方法時,事實上是調(diào)用了IdcSerializer類的create方法偏螺,就是基于Django智能判斷來實現(xiàn)的行疏。
2.4、序列化總結(jié)
1套像、正向序列化
1. 拿到quertset
2. 將quertset給序列化類
serializer = IdcSerializer(idc)
serializer = IdcSerializer(Idc.objects.all(), many=True)
3. 轉(zhuǎn)JSON
JSONRenderer().render(serializer.data)
2酿联、反向序列化
data = JSONRenderer().parse(content)
serializer = IdcSerializer(data=data)
serializer.is_valid()
serializer.save()
正向序列化:從數(shù)據(jù)庫里拿出來數(shù)據(jù),然后返回Json給前端
反向序列化:從前端接口拿到數(shù)據(jù)(data)夺巩,將數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)流贞让,然后序列化驗證后,保存到數(shù)據(jù)庫中柳譬。