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/
五. 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)化欢唾,敬請期待......最后把圖補上