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/

五. 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ǔ)上
