django_rest_framework 入門(mén)筆記:Serializer

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

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

通過(guò)命令行操作如下語(yǔ)句

pip install djangorestframework

看到安裝成功的提示就安裝成功,可以嗨皮的寫(xiě) restful 接口了

創(chuàng)建 django 項(xiàng)目,然后創(chuàng)建一個(gè) app,例如 blog_api (不會(huì)創(chuàng)建請(qǐng)參考 django 部分)

python manage.py startapp blog_api

將新建 app 的信息加入到已有項(xiàng)目中

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

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

創(chuàng)建 serializer 類(lèi)之前,我們需要先在 models.py 文件下創(chuàng)建 model 類(lèi)(參考 django,不詳細(xì)解釋?zhuān)苯由洗a)

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 類(lèi)后需要?jiǎng)?chuàng)建數(shù)據(jù)庫(kù)(參考 django 數(shù)據(jù)庫(kù)遷移部分)

python manage.py makemigrations

python manage.py migrate

做好準(zhǔn)備工作我們就可以創(chuàng)建 serializer 類(lèi),serializer 功能主要是對(duì) model 實(shí)例提供序列化和反序列化的途徑,然后可以轉(zhuǎn)換成為某種表現(xiàn)形式,例如 json 等,其定義的方式和 Form 類(lèi)似,官方的原話(huà)如下

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 類(lèi)需要繼承 serializers.Serializer,
# 然后實(shí)現(xiàn)父類(lèi)的 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 的常用字段類(lèi)型類(lèi)似 Model 類(lèi),可以參考 django model 部分的參數(shù),Serializer 的常用設(shè)置參數(shù)也類(lèi)似 Model 類(lèi),部分不同,例如 model 中的 blank 和 null 在 serializer 中為 allow_blank 和 allow_null,其余類(lèi)似,可以參考 django model 部分的設(shè)置參數(shù)。也可以查看官網(wǎng),Serializer 字段類(lèi)型和參數(shù)

在接下去講下面的內(nèi)容之前,我們先了解一下關(guān)于 Serializer 的常用操作,這邊列出一些常用的功能,可以實(shí)際碼下看看,效果會(huì)比看一遍要好

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 接口入門(mén)', create_time=datetime.datetime.now(),
            modified_time=datetime.datetime.now(), body='Restful 接口入門(mén)',
            excerpt='Restful 接口入門(mén)')
# 保存到數(shù)據(jù)庫(kù)
post.save()
# 對(duì) post 實(shí)例進(jìn)行序列化
serializer = PostSerializer(post)
# 通過(guò) serializer.data 查看序列化后的結(jié)果,是一個(gè)字典
# {'title': 'Restful 接口入門(mén)', 'body': 'Restful 接口入門(mén)', 
# 'create_time': '2018-04-05T21:27:21+08:00', 'modified_time': '2018-04-05T21:27:25+08:00', 
# 'excerpt': 'Restful 接口入門(mén)'}
print(serializer.data)

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

# 如果將 json 轉(zhuǎn)回字典,需要通過(guò) BytesIO 進(jìn)行處理
stream = BytesIO(content)
# 打印結(jié)果同序列化后的結(jié)果
data = JSONParser().parser(stream)

# 將數(shù)據(jù)轉(zhuǎn)換成為實(shí)體類(lèi)對(duì)象
serializer = PostSerializer(data=data)
# 需要檢驗(yàn)是否有效數(shù)據(jù),類(lèi)似 Form
serializer.is_valid()
# 經(jīng)過(guò)驗(yàn)證后的數(shù)據(jù),返回一個(gè) OrderedDict
# OrderedDict([('title', 'Restful 接口入門(mén)'), ('body', 'Restful 接口入門(mén)'),
# ('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 接口入門(mén)')])
print(serializer.validated_data)
# 保存有效的數(shù)據(jù),通常用于 POST 提交的數(shù)據(jù)信息
serializer.save()

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

rest_framework 類(lèi)似 django,需要通過(guò) view 來(lái)展示接口返回的數(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 請(qǐng)求則返回所有的列表
    if request.method == "GET":
        posts = Post.objects.all()
        serializer = PostSerializer(posts, many=True)
        return JsonResponse(serializer.data, safe=False) 
    # 如果是 POST 請(qǐng)求則保存數(shù)據(jù)
    elif request.method == "POST":
         # 將 request 中的參數(shù)取出來(lái)進(jìn)行序列化
        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)
        # 無(wú)效則返回 400 BAD_REQUEST
        return JsonResponse(serializer.errors, status=400)
四. 將視圖函數(shù)關(guān)聯(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 運(yùn)行項(xiàng)目

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

然后通過(guò)網(wǎng)址 http://192.168.x.xxx:8080/api/posts/ 查看 restful 接口,是不是和我們平時(shí)從后臺(tái)獲取的接口很像(肯定像啊,因?yàn)楸緛?lái)就是這樣的啊~~)

列表接口

或者我們也可以通過(guò) httpie 來(lái)進(jìn)行接口查看,其好處是可以直接操作 POST 等操作

首先安裝 httpie pip install httpie

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

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

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

寫(xiě)完第一個(gè) restful 接口,是否發(fā)現(xiàn) model 和 serializer 有很多重復(fù)的代碼,能否進(jìn)行優(yōu)化呢,答案是當(dāng)然可以的

剛才我們的 serializer 類(lèi)繼承 serializers.Serializer 類(lèi),這回我們進(jìn)行修改,通過(guò)繼承 serializers.ModelSeralizer 實(shí)現(xiàn)相同的效果

# ModelSeralizer 會(huì)自動(dòng)幫我們實(shí)現(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 不能同時(shí)設(shè)置
        # exclude = ['id', 'author']

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

別的無(wú)需修改,修改完 serializer 類(lèi)后我們?cè)俅芜\(yùn)行項(xiàng)目,輸入網(wǎng)址查看,我們發(fā)現(xiàn)返回的接口信息完全一樣,關(guān)鍵是我們省了好多好多好多....的重復(fù)代碼,身為程序員,不會(huì)偷懶可不好喔!接著我們需要來(lái)操作對(duì)某篇具體的 post 進(jìn)行信息修改,那就涉及到了 post 的 id,還記得我們?cè)?django 部分如何操作這種 url 的么,忘記了往前翻翻......接著我們通過(guò)一個(gè) detail 方法來(lái)進(jìn)行某篇具體的 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 值獲取對(duì)應(yīng)的 post 實(shí)例
    post = get_object_or_404(Post, pk=pk)
    # 首先判斷是否存在這個(gè) post,不存在直接返回 404 NOT FOUND
    # 如果 settings.py 下的 DEBUG 屬性設(shè)置為 True 的話(huà),django 會(huì)不展示 404 頁(yè)面,設(shè)置成 False 即可
    if post is None:
        return HttpResponse(status=404)
    # 如果 request 是 GET 方法,則直接展示對(duì)應(yīng) pk 的 post
    if request.method == 'GET':
        serializer = PostSerializer(post)
        # 將序列化后的數(shù)據(jù)轉(zhuǎn)換成 json 展示
        return JsonResponse(serializer.data)
    # 如果 request 是 PUT 方法,則解析 request 中的參數(shù),
    # 進(jìn)行校驗(yàn)是否合理,合理則更新,否則返回 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'),
]

我們通過(guò) url 去獲取具體的詳情
獲取詳情

通過(guò)上面的兩個(gè)例子,我們發(fā)現(xiàn) tags 字段返回的信息只有 id,但是很多時(shí)候我們需要具體的信息,如果只返回一個(gè) id 的話(huà)就是說(shuō)我們還要用 tag 的 id 再去做請(qǐng)求獲取具體的 tag 信息,太麻煩了,我們對(duì) model 中存在的 ForeignKey 和 MaynToMany 鏈表結(jié)構(gòu)字段做些必要的調(diào)整,使其能夠返回全部信息。

# 首先我們?cè)?model 中增加兩個(gè)鏈表結(jié)構(gòu)字段,同時(shí)創(chuàng)建相關(guān)的 model 并生成數(shù)據(jù)庫(kù)
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):
    # 會(huì)顯示所有該 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 鏈表結(jié)構(gòu)字段處理,有兩種處理方式,第一種展示 serializer 中設(shè)置的字段,
    # 第二種展示某個(gè)指定字段
    # author = AuthorSerializer(read_only=True)
    author = serializer.ReadOnlyField(source="author.username")
    # ManyToMany 鏈表結(jié)構(gòu)字段處理
    tag = TagSerializer(many=True, read_only=True)
    
    class Meta:
        model = Post
        fields = '__all__'

調(diào)整完后我們?cè)偃ゲ榭唇涌谛畔?,這下全部的信息都顯示出來(lái)了。OK,這部分我們先到這,下一部分我們將通過(guò) DRF 內(nèi)置的視圖函數(shù),視圖類(lèi)對(duì)我們現(xiàn)在 views 中的代碼進(jìn)行優(yōu)化,敬請(qǐng)期待......最后把圖補(bǔ)上
調(diào)整后的列表接口信息
調(diào)整后的詳情接口信息
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容