/django-rest-framework-tutorial

Django-REST-framework 基本教學 - 從無到有 DRF-Beginners-Guide 📝

Primary LanguagePythonMIT LicenseMIT

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

安裝 Django-REST-framework

pip install djangorestframework

基本上安裝應該沒什麼問題。

django-rest-framework 設定

請記得要將 Django-REST-framework 加入設定檔

請在 settings.py 裡面的 INSTALLED_APPS 加入下方程式碼 (下圖)

INSTALLED_APPS = (
    ...
    'rest_framework',
    ...
)

alt tag

建立 Django App

先建立一個觀念,在 Django 中,通常我們會依照 功能 去建議一個 App , 例如範例的 musics ,代表他是 管理音樂 的部份。

有了這個觀念之後,我們動手開始做吧~

請在你的命令提示字元 (cmd ) 底下輸入

python manage.py startapp musics

建立完請記得要將 App 加入設定檔

請在 settings.py 裡面的 INSTALLED_APPS 加入 musics (也就是你自己建立的 App 名稱)

alt tag

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"

alt tag

接著在命令提示字元 (cmd ) 底下輸入

python manage.py makemigrations

alt tag

python manage.py migrate

alt tag

makemigrations : 會幚你建立一個檔案,去記錄你更新了哪些東西。

migrate : 根據 makemigrations 建立的檔案,去更新你的 DATABASE 。

執行完上面的指令之後,

你可以使用SQLiteBrowserPyCharm 觀看 DATABASE,

你會發現多出一個 music 的 table ( 如下圖 )

alt tag

有沒有注意到我們明明在 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')

alt tag

如果你想要全部 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

alt tag

只需要寫這樣,你就擁有 CRUD 的全部功能,是不是非常強大 😮

為什麼呢? 因為 DRF 的 viewsets.ModelViewSet 裡面幫你定義了這些功能,

alt tag

當然,如果你需要,也可以覆寫他。

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))
]

alt tag

最後執行 Django , 然後瀏覽 http://127.0.0.1:8000/api/

你應該會看到如下圖

alt tag

恭喜你,成功了 😄

接下來,讓我來測試 API 吧~

測試 API

在測試 API 之前,大家必須先了解一下什麼是 REST API

REST API 全名為 RESTful API,它並不是一個新東西、新技術,它只是一個規範。

簡單說明 :

GET : 讀取資源

PUT : 替換資源

DELETE : 刪除資源

POST : 新增資源

PATCH : 更新資源部份內容

剩下更詳細的資料就麻煩大家 GOOGLE了,我在現在來 測試 API 😃

測試 API 的工具很多,在這裡我們使用 Postman ,大家可以用自己習慣的工具。

POST

我們先來新增幾筆資料,如下圖

alt tag

在 步驟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/

alt tag

或是你只想看特定的某一筆,可以使用 http://127.0.0.1:8000/api/music/2/

alt tag

PUT

如果你想修改特定資料,可以使用 http://127.0.0.1:8000/api/music/2/

alt tag

當按下 send 之後,會看到 response ( 步驟3 )的地方回傳修改後的值。

DELETE

如果你想刪除特定資料,可以使用 http://127.0.0.1:8000/api/music/3/

alt tag

執行後,你會發現 id=3 的資料被刪除了。

alt tag

授權 (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,)

alt tag

接著在 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'))
]

alt tag

最後執行 Django , 然後瀏覽 http://127.0.0.1:8000/api/ ,你會發現右上角多了 Log in 的按鈕

alt tag

我們先使用我們在 Django 基本教學 - 從無到有 Django-Beginners-Guide 裡面學到的 建立超級使用者

python manage.py createsuperuser

alt tag

讓我們再次使用 POSTMAN,我們用 GET 當作範例

GET 授權

alt tag

有注意到嗎? response 說我沒有 授權,

所以這時候我們就必須再加上授權才能操作 API (如下圖),我們可以操作 API 了

我的 帳號/密碼 設定為 twtrubiks/password123

alt tag

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,還有 FormParserMultiPartParser 等等

更多資訊可參考 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 ,趕快動手下去玩玩吧 😛

如果意猶未盡,延伸閱讀 😆

執行環境

  • Python 3.4.3

Reference

License

MIT license