
- Select a language for the TTS:
- UK English Female
- UK English Male
- US English Female
- US English Male
- Australian Female
- Australian Male
- Language selected: (auto detect) - EN
Play all audios:
前言 自學後端不到一年的時間,主要是使用Django當作框架來架設網站,因為Django裡面已經內涵SqLite,傳輸上相當方便,但是近來和一些前端開發者合作,要使用到API來傳輸,想說藉由這次機會,就趕快來自學一下如何使用Django來開發一個專門傳輸API 的Server。 首先關鍵字是 Django REST frmaework,這個套件滿多人用的,查了一下發現也有
DRF Docs (django-rest-framework-docs) 這個 plugin 可以用來生出 API 的文件,看了一下範例感覺還不錯,於是就放棄用 Flask 自己刻,直接採用 Django + Django REST framework + DRF Docs(SqLite or MySQL) + Django Filter,建立一個可以從 BigQuery
dataset 撈資料出來的 API Server。 DJANGO REST FRAMEWORK 以下為了撰寫方便,直接把 DJANGO REST FRAMEWORK 簡稱為 DRF。 整個 DRF 我覺得設計得滿完整,甚至也有 plugin 的生態系,如果找不到合適的,也可以自己撰寫 DRF 的 plugin。剛開始上手的話有份官方的 Tutorial
可看:Quickstart — Django REST framework,建議把整份 tutorial 都唸完會比較瞭解整個 framework 元件之間的關係,畢竟篇幅也不多,加上 Quickstart 也就 8 個頁面而已。剩下的等實際撰寫程式碼時遇到不太懂的時候,再去查詢官網上詳細一點的文件就行了,有時候真的文件說的不夠清楚的話可能還是得去看一下程式碼。
那我下面也手把手簡短講一下大致的操作流程 PROJECT SETUP * 開一個新的 Django 專案 mimir,然後在裡面開一個新的APP crawler。 p.s 這邊開始就看不懂的人請進Django 介紹 — 手把手學習指南,從頭開始學習。 p.s 上面的名稱請自己創造,不一定要跟我一樣。 * 如果習慣開新環境的人,就在這邊把虛擬環境開一下吧。 *
安裝套件djangorestframework。 # Create the project directory mkdir tutorial cd tutorial# Create a virtual environment to isolate our package dependencies locally python3 -m venv env source
env/bin/activate # On Windows use `env\Scripts\activate`# Install Django and Django REST framework into the virtual environment pip install django pip install djangorestframework# Set up a
new project with a single application django-admin startproject mimir. # Note the trailing '.' character cd tutorial django-admin startapp crawler cd .. 在終端機中把資料庫初始化並且設置superuser。
p.s 如果你是使用已經有的sql檔案,可忽略。 python manage.py migratepython manage.py createsuperuser --email [email protected] --username admin 建立數據庫並創建初始用戶並準備好使用後,我們將進入coding的部分…
我在這邊的範例,是使用自己的資料庫,所以如果你手邊有一個現成的資料庫,可以跟我一起做。 事前準備 如果你有自己的SQL資料庫,但不是原生在Django裡面的話,請你先把資料匯入django裡面的SqLite裡面。(使用 DB Browser 可以幫忙匯出、匯入) MODEL
這邊就是把你SQL裡面檔案的欄位放上來,有什麼就填什麼,資料型態自己要顧好,像是我date就故意用文字格式,而不是時間格式。 from django.db import models# Create your models here. class pttdata(models.Model): date = models.TextField() author =
models.TextField() title = models.TextField() href = models.TextField() pushcount = models.TextField() content = models.TextField()class Meta: db_table =
"PTT_NEWS" SERIALIZERS 再來我們來定義序列化器。這個目的是把你的資料庫中設定的欄位,轉換成可以傳輸的模式。 創建一個mimir/ crawler/ serializers.py的新檔案。程式碼如下。 from django.contrib.auth.models import User, Group from
rest_framework import serializers from crawler.models import pttdata,googledata,yahoodata,stockdata import jsonclass GroupSerializer(serializers.HyperlinkedModelSerializer): class Meta:
model = pttdata fields = ['date', 'author','title','href','pushcount','content']
fields裡面的元素就是你想輸出的東西,在這邊可以在自己斟酌選擇一下,看你要全部輸入,還是部份輸入就好。 然後記得要從Model那邊import 資料庫過來唷!!!!! VIEWS 打開mirmir/ crawler/ views.py並輸入內容。 from rest_framework import viewsets from crawler.serializers
import GroupSerializer from crawler.models import pttdata from rest_framework import generics import django_filters.rest_framework from rest_framework.pagination import PageNumberPagination
from rest_framework import filtersclass StandardPagination(PageNumberPagination): page_size = 10 page_size_query_param = "page"class PostViewSet(viewsets.ModelViewSet):
pagination_class = StandardPaginationclass GroupViewSet(viewsets.ModelViewSet):lookup_url_kwarg = "title" serializer_class = GroupSerializerdef get_queryset(self):
queryset = pttdata.objects.all() username = self.request.query_params.get('title', None)if username is not None: queryset =
queryset.filter(title__contains=str(username)) return queryset 這邊class StandardPagination(PageNumberPagination)是用來控制最後輸出API介面,是一次顯示全部還是數個資料。控制變因為page_size page_size = 10
page_size_query_param = “page” 如果不想設置Filter功能的話後面可以這樣寫 class GroupViewSet(viewsets.ModelViewSet): serializer_class = GroupSerializer def get_queryset(self): queryset =
pttdata.objects.all() return queryset 而我上面的寫法,則是可以在最後用url的方式把需要的資料塞選出來。 如果你要一次塞選很多變數。可以這樣寫 class GroupViewSet(viewsets.ModelViewSet):lookup_url_kwarg = "title"
serializer_class = GroupSerializerdef get_queryset(self): queryset = pttdata.objects.all() username = self.request.query_params.get('title', None) date=
self.request.query_params.get('date', None)if username is not None: queryset = queryset.filter(title__contains=str(username)) queryset =
queryset.filter(date__contains=str(date)) return queryset ****title__contains後面加__contains的意思是相似,如果你要完全相同的話,就把__contains去掉就可以了。 URLS 好~~~那我們進行到 API URLs 這一步. GOto mimir/urls.py... from
django.urls import include, path from rest_framework import routers from crawler import views from django.conf.urls import urlrouter = routers.DefaultRouter()
router.register(r'pttdata', views.GroupViewSet, basename='title') # Wire up our API using automatic URL routing. # Additionally, we include login URLs for the browsable
API. urlpatterns = [ path('', include(router.urls)), #path('api/v1/', include(router.urls)), path('api-auth/',
include('rest_framework.urls', namespace='rest_framework')), # path('pttdata/', views.GroupViewSet.as_view) ]
url的設定要注意的部分就是名稱設定了,做到現在不知道你有沒有亂掉…如果沒有的話,已經快完成了加油。 PAGINATION 我們剛剛在view寫的分頁可讓您控制每頁返回多少個對象。 要啟用它,請將以下程式碼添加到mimir/settings.py REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10 } SETTINGS 要像加入APP一樣,把這個 'rest_framework' 加進去INSTALLED_APPS. mimir/settings.py
INSTALLED_APPS = [ ... 'rest_framework', ] 呼!!!大功告成 網頁url這邊?title=台積電 問號後面放的是你自己設定的Filter變數 ,等號後面隨便你放,但是這邊要注意一點,如果你是塞選文字的話,在view那邊記得要把get後的東西轉成str才可以用喔。我這邊卡了一下。
這邊紀錄一下幾個我自己在閱讀文件的時候花比較多時間理解的部份: * 1 — Serialization — Django REST framework * 基本上就是在 Django 的 Model 上再多做一層包裝,可以對 API 做一些客製化設定,比如要顯示哪些欄位、限定哪些權限…等等。 * Filtering — Django REST framework *
如果要針對不同的使用者得到不同的結果的話,就會需要用到 filtering 的部份。 * 可以針對使用者、網址、可使用參數做限制。 * 有多種不同的 filter 可以用,搜尋、排序、權限,也可以自己繼承下來撰寫客製化的 filter。 * Routers — Django REST framework * 基本上跟 Django 的 dispatcher
寫法差不多,但多了一些可以針對 HTTP method 的設定等等。 * django-rest-framework/viewsets.py at master · encode/django-rest-framework · GitHub * 當時是因為對 ViewSet 可以使用的參數不太清楚,看文件又看不出個所以然,所以就跑去看程式碼了。
花了一點時間熟悉之後,我在後續使用上遇到最大的問題是在效能,因為我要去查詢的資料總量滿大的,所以查詢常常都會等很久。還有 DRF 預設的 pagination 部份也沒有處理得很好,查了一下發現也有很多人遇到,所以有滿多文章在講這件事的,這裡列出我自己覺得比較有用的: * Ditching Django REST Framework Serializers for Serpy
· BetterWorks Engineering Blog * 這篇是作者因為 DRF 的 Serializer 實在是太慢,所以自己寫了另外一個作 serialization 的 library: serpy * Optimizing slow Django REST Framework performance * 這篇是在講怎麼透過調整 DRF 的 Serializer
來處理 query 時過慢的問題。 * 要用上 queryset.prefech_realted 等等。 * Web API performance: profiling Django REST framework * 這篇是作者使用了 DRF 並測試其效能以後自己歸納出的一些結論,基本上是推薦使用 DRF,算是我看過最完整對 DRF 做效能測試的文章了。 * 一些迷思: *
自己寫個框架:即便只有用到 DRF 的 APIView 其他都沒用到,還是推薦使用 DRF,比起你自己用 Django 撰寫的 API 還是好上許多。 * 想用輕量化的框架:DRF 雖然包含了很多功能,但核心的 view 部份是很簡單的。 * DRF 會被 Django 的 model 綁住:view 和 serializer 都是可選的,沒有強制綁定。 *
Django/Python/DRF 太慢:這篇文章會大量討論效能的部份,基本上都可以透過適當的資料庫查詢結果暫存、設計良好的 HTTP 暫存以及 shared server-side cache 來解決。 結論 如果熟 Django 的人真的可以很快用 DRF + DRF Docs 弄出一個可以做帳號權限管理的 REST API 網站,而且因為用上了 DRF
Docs,所以不會出現程式碼和文件不一致的狀況。 但如果不考慮快速完成而是考慮效能的話,我大概就不太推薦 DRF,雖然不確定目前效能改善到什麼地步,如果還是要使用的話可能就要在 Database 或架構方面多下點功夫。 因為開發完這網站之後我就沒再碰 DRF 了,所以這篇文章可能會顯得有點過時些,但可以當個參考,畢竟這篇主要目的是紀錄給我自己知道到底我把時間花在哪裡了。
技術文這種東西真的不太能囤積在草稿啊,能發就要趕快發,不然真的很容易過時。如果是一些跟人比較有關係的文章則大概很難過時,看看技術的長青書基本上都是在講人的態度或是做事的方法與原則。其實也在思考以後寫的一些技術文能否能朝這個方向去多紀錄一些。 其他參考資料
https://blog.typeart.cc/django%E8%88%87django%20REST%20framework(DRF)%E9%96%8B%E7%99%BC%E7%AD%86%E8%A8%98/