django-rest-framework-tutorial
Django-REST-framework 基本教學 - 從無到有 DRF-Beginners-Guide 📝
透過 Django REST framework ( DRF ) 建立 REST API 非常方便快速,
REST API ? 這是什麼,可以吃嗎 ? 如果你想先對 REST API 有一些認識,可參考之前寫的 認識 RESTful API
在這裡教大家建立自己的第一個 Django-REST-framework 😄
建議對 Django 還不熟的人,可以先閱讀我之前寫的 Django 基本教學 - 從無到有 Django-Beginners-Guide,
先建立一些基本觀念,再來看 DRF 會比較清楚。
教學
請先確認電腦有安裝 Python
請在你的命令提示字元 (cmd ) 底下輸入
安裝 Django
pip install django
pip install djangorestframework
基本上安裝應該沒什麼問題。
django-rest-framework 設定
請記得要將 Django-REST-framework 加入設定檔
請在 settings.py 裡面的 INSTALLED_APPS 加入下方程式碼 (下圖)
INSTALLED_APPS = (
...
'rest_framework',
...
)
建立 Django App
先建立一個觀念,在 Django 中,通常我們會依照 功能 去建議一個 App , 例如範例的 musics ,代表他是 管理音樂 的部份。
有了這個觀念之後,我們動手開始做吧~
請在你的命令提示字元 (cmd ) 底下輸入
python manage.py startapp musics
建立完請記得要將 App 加入設定檔
請在 settings.py 裡面的 INSTALLED_APPS 加入 musics (也就是你自己建立的 App 名稱)
Models
定義出資料庫中的結構(schema),並且透過 Django 中的指令去建立資料庫。
Django 預設是使用 SQLite ,如果想要修改為其他的資料庫,可以在 settings.py 裡面進行修改。
首先,請先在 models.py 裡面增加下方程式碼 (下圖)
from django.db import models
# Create your models here.
class Music(models.Model):
song = models.TextField()
singer = models.TextField()
last_modify_date = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "music"
接著在命令提示字元 (cmd ) 底下輸入
python manage.py makemigrations
python manage.py migrate
makemigrations : 會幚你建立一個檔案,去記錄你更新了哪些東西。
migrate : 根據 makemigrations 建立的檔案,去更新你的 DATABASE 。
執行完上面的指令之後,
你可以使用SQLiteBrowser 或 PyCharm 觀看 DATABASE,
你會發現多出一個 music 的 table ( 如下圖 )
有沒有注意到我們明明在 models.py 裡面就沒有輸入 id ,可是 database 裡面卻有 id 欄位,
這是因為 Django 預設會幫你帶入,所以可以不用設定。
Serializers 序列化
Serializers 序列化 是 DRF 很重要的一個地方 ⭐
主要功能是將 Python 結構序列化為其他格式,例如我們常用的 JSON。
在 musics 裡面新增 serializers.py,並輸入下方程式碼
from rest_framework import serializers
from musics.models import Music
class MusicSerializer(serializers.ModelSerializer):
class Meta:
model = Music
# fields = '__all__'
fields = ('id', 'song', 'singer', 'last_modify_date', 'created')
如果你想要全部 fields ,可以使用第 8 行的寫法。
2017/9/8 新增
增加 SerializerMethodField
使用方法 ,可參考 serializers.py, days_since_created 為例
class MusicSerializer(serializers.ModelSerializer):
days_since_created = serializers.SerializerMethodField()
class Meta:
model = Music
# fields = '__all__'
fields = ('id', 'song', 'singer', 'last_modify_date', 'created', 'days_since_created')
def get_days_since_created(self, obj):
return (now() - obj.created).days
更多說明請參考 http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
Views
在 Django 基本教學 - 從無到有 Django-Beginners-Guide 中我們使用 views,
而在 DRF 中提供我們可以使用另一種稱為 viewsets 。
請在 views.py 裡輸入下方程式碼 (下圖)
# Create your views here.
from musics.models import Music
from musics.serializers import MusicSerializer
from rest_framework import viewsets
# Create your views here.
class MusicViewSet(viewsets.ModelViewSet):
queryset = Music.objects.all()
serializer_class = MusicSerializer
只需要寫這樣,你就擁有 CRUD 的全部功能,是不是非常強大 😮
為什麼呢? 因為 DRF 的 viewsets.ModelViewSet 裡面幫你定義了這些功能,
當然,如果你需要,也可以覆寫他。
Routers 路由
DRF 提供 DefaultRouter 讓我們快速建立 Routers 路由。
請先將 urls.py 裡面增加一些程式碼,如下圖
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework.routers import DefaultRouter
from musics import views
router = DefaultRouter()
router.register(r'music', views.MusicViewSet)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(router.urls))
]
最後執行 Django , 然後瀏覽 http://127.0.0.1:8000/api/
你應該會看到如下圖
恭喜你,成功了 😄
接下來,讓我來測試 API 吧~
測試 API
在測試 API 之前,大家必須先了解一下什麼是 REST API
REST API 全名為 RESTful API,它並不是一個新東西、新技術,它只是一個規範。
簡單說明 :
GET : 讀取資源
PUT : 替換資源
DELETE : 刪除資源
POST : 新增資源
PATCH : 更新資源部份內容
剩下更詳細的資料就麻煩大家 GOOGLE了,我在現在來 測試 API 😃
測試 API 的工具很多,在這裡我們使用 Postman ,大家可以用自己習慣的工具。
POST
我們先來新增幾筆資料,如下圖
在 步驟1 的地方輸入你的 API 的網址,範例為 http://127.0.0.1:8000/api/music/
在 步驟2 body 的地方,填入 song 和 singer 的值,然後按下 Send,
接著看 response ( 步驟3 ),也就是你新增進去 dabase 的資料。
GET
如果你想一次看裡面全部的資料,可以使用 http://127.0.0.1:8000/api/music/
或是你只想看特定的某一筆,可以使用 http://127.0.0.1:8000/api/music/2/
PUT
如果你想修改特定資料,可以使用 http://127.0.0.1:8000/api/music/2/
當按下 send 之後,會看到 response ( 步驟3 )的地方回傳修改後的值。
DELETE
如果你想刪除特定資料,可以使用 http://127.0.0.1:8000/api/music/3/
執行後,你會發現 id=3 的資料被刪除了。
授權 (Authentications )
在 REST API 中,授權很重要,如果沒有授權,別人一直任意不受限制的操作你的 API ,很危險,
所以 DRF 有提供 Authentications,讓我們來試試看吧~
首先,請在 views.py 裡面新增 permission_classes
# Create your views here.
from musics.models import Music
from musics.serializers import MusicSerializer
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
# Create your views here.
class MusicViewSet(viewsets.ModelViewSet):
queryset = Music.objects.all()
serializer_class = MusicSerializer
permission_classes = (IsAuthenticated,)
接著在 urls.py 裡面增加 api-auth
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework.routers import DefaultRouter
from musics import views
router = DefaultRouter()
router.register(r'music', views.MusicViewSet)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
最後執行 Django , 然後瀏覽 http://127.0.0.1:8000/api/ ,你會發現右上角多了 Log in 的按鈕
我們先使用我們在 Django 基本教學 - 從無到有 Django-Beginners-Guide 裡面學到的 建立超級使用者
python manage.py createsuperuser
讓我們再次使用 POSTMAN,我們用 GET 當作範例
GET 授權
有注意到嗎? response 說我沒有 授權,
所以這時候我們就必須再加上授權才能操作 API (如下圖),我們可以操作 API 了
我的 帳號/密碼 設定為 twtrubiks/password123
2017/12/3 新增
上面的方法是針對整個 class
設定權限,那我們可不可以依照 method 呢?
幾個例子,我希望 GET 時不用權限,但是 POST 時就需要權限,這樣該怎麼做呢?
可以參考 shares/views.py
class ShareViewSet(viewsets.ModelViewSet):
queryset = Share.objects.all()
serializer_class = ShareSerializer
parser_classes = (JSONParser,)
def get_permissions(self):
if self.action in ('create',):
self.permission_classes = [IsAuthenticated]
return [permission() for permission in self.permission_classes]
# [GET] api/shares/
def list(self, request, **kwargs):
users = Share.objects.all()
serializer = ShareSerializer(users, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
# [POST] api/shares/
@permission_classes((IsAuthenticated,))
def create(self, request, **kwargs):
name = request.data.get('name')
users = Share.objects.create(name=name)
serializer = ShareSerializer(users)
return Response(serializer.data, status=status.HTTP_201_CREATED)
透過裝飾器permission_classes
來為我們的 method 分別設定權限,並且有一個
get_permissions
來決定是否需要權限(在這裡設定 create
, 也就是 POST)。
這個例子就是 GET 時不用權限,但是 POST 時就需要權限。
更多詳細介紹可參考官網 authentication
Parsers
在 REST framework 中有一個 Parser classes ,這個 Parser classes 主要是能控制接收的 Content-Type ,
例如說我規定 Content-Type 只接受 application/json ,這樣你就不能傳其他的 Content-Type ( 舉例 : text/plain ) 。
通常如果沒有特別去設定 ,一般預設是使用 application / x-www-form-urlencode ,不過預設的可能不是你想要的或是
說你想要設計只允許規範一種 Content-Type 。
設定 Parsers 也很簡單,如果你希望全域的設定,可以加在 settings.py,
這樣就代表我只允許 Content-Type 是 application/json 。
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
)
}
也可以針對特定 view 或 viewsets 加以設定 ,直接在 views.py 加上 parser_classes 即可
class MusicViewSet(viewsets.ModelViewSet):
queryset = Music.objects.all()
serializer_class = MusicSerializer
permission_classes = (IsAuthenticated,)
parser_classes = (JSONParser,)
當然,parser_classes 不只有 JSONParser,還有 FormParser , MultiPartParser 等等
更多資訊可參考 http://www.django-rest-framework.org/api-guide/parsers/#parsersr
Extra link and actions
我們使用 REST framework 時,難免會有想要制定額外的 route ,這時候我們可以利用
@detail_route
或 @list_route
。
範例程式碼可參考 views.py
detail_route
使用方法很簡單,直接加上裝飾器 @detail_route
即可
@detail_route(methods=['get'])
def detail(self, request, pk=None):
music = get_object_or_404(Music, pk=pk)
result = {
'singer': music.singer,
'song': music.song
}
return Response(result, status=status.HTTP_200_OK)
以上面這個例子來說, URL pattern: /api/music/{pk}/detail/
,
如果你沒有額外指定,通常你的 url_path 就是你 function 命名的名稱,
當然,我們也可以自己額外定義 url_path,只需要加上 url_path 參數,
範例如下
@detail_route(methods=['get'], url_path='detail_self')
def detail(self, request, pk=None):
music = get_object_or_404(Music, pk=pk)
result = {
'singer': music.singer,
'song': music.song
}
return Response(result, status=status.HTTP_200_OK)
以上面這個例子來說, URL pattern: /api/music/{pk}/detail_self/
,
這樣就不會使用你的 function 做為 url_path 了。
list_route
使用方法很簡單,直接加上裝飾器 @list_route
即可
@list_route(methods=['get'])
def all_singer(self, request):
music = Music.objects.values_list('singer', flat=True).distinct()
return Response(music, status=status.HTTP_200_OK)
以上面這個例子來說,URL pattern: /api/music/all_singer/
他也有 url_path 的特性,如果要自定義,只需要加上 url_path 參數。
看完了以上的例子,相信大家可以分辨 @detail_route
以及 @list_route
的不同。
更多資訊可參考 http://www.django-rest-framework.org/api-guide/routers/#extra-link-and-actions
Testing
先簡單介紹一下大家常聽到的 TDD 以及 BDD
TDD : Test-Driven Development。
BDD : Behavior-driven development 。
詳細地請大家再自行 GOOGLE,這邊要講 DRF 的 Testing,
你也可以參考官網的教學 http://www.django-rest-framework.org/api-guide/testing/
或是你也可以參考我寫的範例 tests.py
Test Case Scenarios
- Create a music with API.
- Retrieve a music with API.
- Partial Update a music with API.
- Update a music with API.
- Delete a music with API.
- Retrieve a music detail with API.
- Get All singer with API.
API Endpoints
Music
-
/api/music/ (Music create and list endpoint)
-
/api/music/{music-id}/ (Music retrieve, update and partial update and destroy endpoint)
-
/api/music/{music-id}/detail/ (Music retrieve detail endpoint)
-
/api/music/all_singer/ (Music list singer endpoint)
Usage
python manage.py test
因為本範例剛好只有建立一個 APP ,如果你有很多個 APP ,你也可以指定
你要測試的 APP,範例如下
python manage.py test [app 名稱]
python manage.py test musics
後記
恭喜你,基本上到這裡,已經是一個非常簡單的 Django-REST-framework ,趕快動手下去玩玩吧 😛
如果意猶未盡,延伸閱讀 😆
-
DRF-dataTable-Example-server-side - DataTables Example (server-side) - Python Django REST framework
-
Deploying_Django_To_Heroku_Tutorial - Deploying a Django App To Heroku Tutorial
執行環境
- Python 3.4.3
Reference
License
MIT license