django_rest_framework 入門筆記:Serializer

django 及 rest_framework 筆記鏈接如下:
django 入門筆記:環(huán)境及項目搭建
django 入門筆記:數(shù)據(jù)模型
django 入門筆記:視圖及模版
django 入門筆記:Admin 管理系統(tǒng)及表單
django 入門筆記:通用視圖類重構視圖
django_rest_framework 入門筆記:Serializer
django_rest_framework 入門筆記:視圖函數(shù)重構
django_rest_framework 入門筆記:分頁与帆,多條件篩選及權限認證設置
django 自帶 user 字段擴展及頭像上傳

一. rest_framework 環(huán)境配置

通過命令行操作如下語句

pip install djangorestframework

看到安裝成功的提示就安裝成功永部,可以嗨皮的寫 restful 接口了

創(chuàng)建 django 項目铅匹,然后創(chuàng)建一個 app撰洗,例如 blog_api (不會創(chuàng)建請參考 django 部分)

python manage.py startapp blog_api

將新建 app 的信息加入到已有項目中

在 settings.py 中的 INSTALLED_APPS 列表中加入如下

INSTALLED_APPS = [
    # ....
    'rest_framework',
    'blog_api',
    # ....
]
二. 創(chuàng)建 rest 的 Serializers 類

創(chuàng)建 serializer 類之前敏沉,我們需要先在 models.py 文件下創(chuàng)建 model 類(參考 django呀袱,不詳細解釋,直接上代碼)

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=70)
    body = models.TextField()
    create_time = models.DateTimeField(auto_now_add=True)
    modified_time = models.DateTimeField()
    excerpt = models.CharField(max_length=200, blank=True)
    
    def __str__(self):
        return self.title
    
    def save(self, *args, **kwargs):
        if not self.excerpt:
            self.excerpt = strip_tags(self.body)[:50]
        super(Post, self).save(*args, **kwargs)

創(chuàng)建完 model 類后需要創(chuàng)建數(shù)據(jù)庫(參考 django 數(shù)據(jù)庫遷移部分)

python manage.py makemigrations

python manage.py migrate

做好準備工作我們就可以創(chuàng)建 serializer 類件蚕,serializer 功能主要是對 model 實例提供序列化和反序列化的途徑孙技,然后可以轉換成為某種表現(xiàn)形式,例如 json 等排作,其定義的方式和 Form 類似牵啦,官方的原話如下

The first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as json. We can do this by declaring serializers that work very similar to Django's forms.

from rest_framework import serializers
from .models import Post

# serializer 類需要繼承 serializers.Serializer,
# 然后實現(xiàn)父類的 update妄痪,create 方法
class PostSerializer(serializers.Serializer):
    # 聲明需要被序列化和反序列化的字段哈雏,同 model 的字段,
    # 字段名注意需要同 model 字段同名
    title = serializers.CharField(max_length=70)
    body = serializers.CharField()
    create_time = serializers.DateTimeField()
    modified_time = serializers.DateTimeField()
    excerpt = serializers.CharField(max_length=200, allow_blank=True)
    
    # 定義創(chuàng)建方法
    def create(self, validated_date):
        return Post.objects.all()
    
    # 定義修改方法
    def update(self, instance, validated_date):
        instance.title = validated_data.get('title', instance.title)
        instance.body = validated_data.get('body', instance.body)
        instance.create_time = validated_data.get('create_time', instance.create_time)
        instance.modified_time = validated_data.get('modified_time', instance.modified_time)
        instance.excerpt = validated_data.get('excerpt', instance.excerpt)

Serializer 的常用字段類型類似 Model 類衫生,可以參考 django model 部分的參數(shù)裳瘪,Serializer 的常用設置參數(shù)也類似 Model 類趋翻,部分不同这溅,例如 model 中的 blank 和 null 在 serializer 中為 allow_blank 和 allow_null,其余類似岛啸,可以參考 django model 部分的設置參數(shù)泪酱。也可以查看官網(wǎng)派殷,Serializer 字段類型和參數(shù)

在接下去講下面的內容之前还最,我們先了解一下關于 Serializer 的常用操作,這邊列出一些常用的功能毡惜,可以實際碼下看看拓轻,效果會比看一遍要好

from .models import Post
from .serializers import PostSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from django.utils.six import BytesIO
import datetime

# 創(chuàng)建數(shù)據(jù)(參考 django model 部分)
post = Post(title='Restful 接口入門', create_time=datetime.datetime.now(),
            modified_time=datetime.datetime.now(), body='Restful 接口入門',
            excerpt='Restful 接口入門')
# 保存到數(shù)據(jù)庫
post.save()
# 對 post 實例進行序列化
serializer = PostSerializer(post)
# 通過 serializer.data 查看序列化后的結果,是一個字典
# {'title': 'Restful 接口入門', 'body': 'Restful 接口入門', 
# 'create_time': '2018-04-05T21:27:21+08:00', 'modified_time': '2018-04-05T21:27:25+08:00', 
# 'excerpt': 'Restful 接口入門'}
print(serializer.data)

# 通過 JSONRenderer 將序列化的數(shù)據(jù)渲染成 json 格式的數(shù)據(jù)
content = JSONRenderer().render(serializer.data)
# b'{"title":"Restful 接口入門","body":"Restful 接口入門",
# "create_time":"2018-04-05T21:27:21+08:00",
# "modified_time":"2018-04-05T21:27:25+08:00","excerpt":"Restful 接口入門"}'
print(content)

# 如果將 json 轉回字典经伙,需要通過 BytesIO 進行處理
stream = BytesIO(content)
# 打印結果同序列化后的結果
data = JSONParser().parser(stream)

# 將數(shù)據(jù)轉換成為實體類對象
serializer = PostSerializer(data=data)
# 需要檢驗是否有效數(shù)據(jù)扶叉,類似 Form
serializer.is_valid()
# 經過驗證后的數(shù)據(jù),返回一個 OrderedDict
# OrderedDict([('title', 'Restful 接口入門'), ('body', 'Restful 接口入門'),
# ('create_time', datetime.datetime(2018, 4, 5, 21, 27, 21,
# tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)), 
# ('modified_time', datetime.datetime(2018, 4, 5, 21, 27, 25,
# tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)), 
# ('excerpt', 'Restful 接口入門')])
print(serializer.validated_data)
# 保存有效的數(shù)據(jù)橱乱,通常用于 POST 提交的數(shù)據(jù)信息
serializer.save()

# 除了序列化模型實例辜梳,也可以將 queryset 進行序列化粱甫,此時需要在 serializer 中加入 many=True
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
# 返回 OrderedDict 列表
print(serializer.data)
三. 創(chuàng)建 rest 的 view 函數(shù)

rest_framework 類似 django泳叠,需要通過 view 來展示接口返回的數(shù)據(jù)信息,在 views.py 中創(chuàng)建視圖函數(shù)

from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from django.http import JsonResponse
from .models import Post
from .serializers import PostSerializer

@csrf_exempt
def post_list(request):
    # 如果是 GET 請求則返回所有的列表
    if request.method == "GET":
        posts = Post.objects.all()
        serializer = PostSerializer(posts, many=True)
        return JsonResponse(serializer.data, safe=False) 
    # 如果是 POST 請求則保存數(shù)據(jù)
    elif request.method == "POST":
         # 將 request 中的參數(shù)取出來進行序列化
        data = JSONParser().parse(request)
        serializer = PostSerializer(data=data)
         # 判斷是否有效的數(shù)據(jù)
        if serializer.is_valid():
            # 有效數(shù)據(jù)保存茶宵,返回 201 CREATED
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        # 無效則返回 400 BAD_REQUEST
        return JsonResponse(serializer.errors, status=400)
四. 將視圖函數(shù)關聯(lián)到 url

創(chuàng)建 urls.py 文件危纫,然后在 project 下的 urls.py 文件中配置 url (參考 django 部分)

# project 下的 urls
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 配置 blog_api 的 url
    url(r'^api/', include('blog_api.urls', namespace='api')),
]
# blog_api 下的 urls
from django.conf.urls import url
from . import views

# 必須加上,且同 project 下 urls 中的 namespace 同值
app_name = 'api'

urlpatterns = [
    url(r'^posts/$', views.post_list, name="api_posts"),
]

配置完 url 運行項目

python manage.py runserver 192.168.x.xxx:8080

然后通過網(wǎng)址 http://192.168.x.xxx:8080/api/posts/ 查看 restful 接口乌庶,是不是和我們平時從后臺獲取的接口很像(肯定像啊种蝶,因為本來就是這樣的啊~~)

列表接口

或者我們也可以通過 httpie 來進行接口查看,其好處是可以直接操作 POST 等操作

首先安裝 httpie pip install httpie

然后通過命令行輸入網(wǎng)址瞒大,前面加上 http 即可

http http://192.168.x.xxx:8080/api/posts/

然后可以查看接口返回的數(shù)據(jù)螃征,效果如下
httpie 獲取的列表接口
五. Serializer 的第一次優(yōu)化調整

寫完第一個 restful 接口,是否發(fā)現(xiàn) model 和 serializer 有很多重復的代碼透敌,能否進行優(yōu)化呢盯滚,答案是當然可以的

剛才我們的 serializer 類繼承 serializers.Serializer 類,這回我們進行修改酗电,通過繼承 serializers.ModelSeralizer 實現(xiàn)相同的效果

# ModelSeralizer 會自動幫我們實現(xiàn) update 和 create 方法
class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        # result 接口需要返回的字段魄藕,可以指定 "__all__" 展示全部參數(shù)
        fields = ['title', 'body', 'create_time', 'modified_time', 'excerpt']
        # exclude 為不展示的字段名,和 fields 不能同時設置
        # exclude = ['id', 'author']

# 通過繼承 serializers.ModelSeralizer 實現(xiàn)的 serializer 其字段可以通過如下進行查看
serializer = PostSerializer()
print(repr(serializer))

別的無需修改撵术,修改完 serializer 類后我們再次運行項目背率,輸入網(wǎng)址查看,我們發(fā)現(xiàn)返回的接口信息完全一樣嫩与,關鍵是我們省了好多好多好多....的重復代碼寝姿,身為程序員,不會偷懶可不好喔划滋!接著我們需要來操作對某篇具體的 post 進行信息修改饵筑,那就涉及到了 post 的 id,還記得我們在 django 部分如何操作這種 url 的么古毛,忘記了往前翻翻......接著我們通過一個 detail 方法來進行某篇具體的 post 的接口操作

from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse, HttpResponse
from rest_framework.parsers import JSONParser
from .models import Post
from .serializers import PostSerializer

@csrf_exempt
def post_detail(request, pk):
    # 根據(jù) pk 值獲取對應的 post 實例
    post = get_object_or_404(Post, pk=pk)
    # 首先判斷是否存在這個 post翻翩,不存在直接返回 404 NOT FOUND
    # 如果 settings.py 下的 DEBUG 屬性設置為 True 的話都许,django 會不展示 404 頁面,設置成 False 即可
    if post is None:
        return HttpResponse(status=404)
    # 如果 request 是 GET 方法嫂冻,則直接展示對應 pk 的 post
    if request.method == 'GET':
        serializer = PostSerializer(post)
        # 將序列化后的數(shù)據(jù)轉換成 json 展示
        return JsonResponse(serializer.data)
    # 如果 request 是 PUT 方法胶征,則解析 request 中的參數(shù),
    # 進行校驗是否合理桨仿,合理則更新睛低,否則返回 400 BAD REQUEST
    elif request.method == 'PUT':
        data = JSONParser().parser(request)
        # 更新 post 的值
        serializer = PostSerializer(post, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data)
        return JsonResponse(serializer.errors, status=400)
    # 如果 request 是 DELETE 方法,則直接刪除
    elif request.method == 'DELETE':
        post.delete()
        return HttpResponse(status=204)

url 配置 detail 界面

app_name = 'api'

urlpatterns = [
    url(r'^posts/$', views.post_list, name="api_posts"),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='api_post'),
]

我們通過 url 去獲取具體的詳情
獲取詳情

通過上面的兩個例子服傍,我們發(fā)現(xiàn) tags 字段返回的信息只有 id钱雷,但是很多時候我們需要具體的信息,如果只返回一個 id 的話就是說我們還要用 tag 的 id 再去做請求獲取具體的 tag 信息吹零,太麻煩了罩抗,我們對 model 中存在的 ForeignKey 和 MaynToMany 鏈表結構字段做些必要的調整,使其能夠返回全部信息灿椅。

# 首先我們在 model 中增加兩個鏈表結構字段套蒂,同時創(chuàng)建相關的 model 并生成數(shù)據(jù)庫
class PostModel(models.Model):
    # ....
    author = models.ForeignKey(Author, related_name='posts', on_delete=models.CASCADE)
    tags = models.ManyToMany(Tag, related_name='posts', blank=True)
    
class Author(models.Model):
    username = models.CharField(max_length=100)
    
class Tag(models.Model):
    name = models.CharField(max_length=100)
# 然后我們需要給新增的 model 創(chuàng)建 serializer
class AuthorSerializer(serializers.ModelSerializer):
    # 會顯示所有該 author 下的 posts
    posts = serializers.PrimaryKeyRelatedField(many=True, queryset=Post.objects.all())
    
    class Meta:
        model = Author
        fields = '__all__'
        
class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = '__all__'
        
class PostSerializer(serializer.ModelSerializer):
    # ForeignKey 鏈表結構字段處理,有兩種處理方式茫蛹,第一種展示 serializer 中設置的字段操刀,
    # 第二種展示某個指定字段
    # author = AuthorSerializer(read_only=True)
    author = serializer.ReadOnlyField(source="author.username")
    # ManyToMany 鏈表結構字段處理
    tag = TagSerializer(many=True, read_only=True)
    
    class Meta:
        model = Post
        fields = '__all__'

調整完后我們再去查看接口信息,這下全部的信息都顯示出來了婴洼。OK骨坑,這部分我們先到這,下一部分我們將通過 DRF 內置的視圖函數(shù)柬采,視圖類對我們現(xiàn)在 views 中的代碼進行優(yōu)化欢唾,敬請期待......最后把圖補上
調整后的列表接口信息
調整后的詳情接口信息
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市警没,隨后出現(xiàn)的幾起案子匈辱,更是在濱河造成了極大的恐慌,老刑警劉巖杀迹,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡脸,死亡現(xiàn)場離奇詭異,居然都是意外死亡树酪,警方通過查閱死者的電腦和手機浅碾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來续语,“玉大人垂谢,你說我怎么就攤上這事〈眩” “怎么了滥朱?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵根暑,是天一觀的道長。 經常有香客問我徙邻,道長排嫌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任缰犁,我火速辦了婚禮淳地,結果婚禮上,老公的妹妹穿的比我還像新娘帅容。我一直安慰自己颇象,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布并徘。 她就那樣靜靜地躺著遣钳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饮亏。 梳的紋絲不亂的頭發(fā)上耍贾,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音路幸,去河邊找鬼。 笑死付翁,一個胖子當著我的面吹牛简肴,可吹牛的內容都是我干的。 我是一名探鬼主播百侧,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼砰识,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了佣渴?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤膨处,失蹤者是張志新(化名)和其女友劉穎真椿,沒想到半個月后突硝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體置济,經...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了樊销。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脏款。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡撤师,死狀恐怖,靈堂內的尸體忽然破棺而出腺占,到底是詐尸還是另有隱情痒谴,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布意鲸,位于F島的核電站尽爆,受9級特大地震影響,放射性物質發(fā)生泄漏槐雾。R本人自食惡果不足惜幅狮,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一钻注、第九天 我趴在偏房一處隱蔽的房頂上張望配猫。 院中可真熱鬧泵肄,春花似錦、人聲如沸品追。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哪雕。三九已至斯嚎,卻和暖如春挨厚,著一層夾襖步出監(jiān)牢的瞬間疫剃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工慌申, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蹄溉。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓您炉,卻偏偏與公主長得像柒爵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子棉胀,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內容