使用 Django REST Framework 和 React 建置開發環境

Django React Django REST

圖片來源:套用 Canva 模板(@veronikagotovceva)

使用 Django 的過程中,覺得 Django 亦適合採用前後端分離的開發模式,因此自己建了基礎 React 為前端、Django 為後端的網頁專案,建置的過程接下來會逐一解說 ( ˶’ᵕ’˶)

也可以到我的 GitHub 看完成的程式碼

開始之前

請確認安裝了以下項目:

  • Python(version >=3.8)
  • Poetry(Django 套件管理工具)
  • NPM(React 套件管理工具)

建立 React

1. 到專案資料夾內,使用終端機輸入以下指令:

1
$ npm create vite@latest frontend -- --template react

這條指令的作用是:

  • 使用 npm(套件管理工具)下載最新的 Vite(打包器),並建立一個名為 frontend 的 React 框架。(當然你也可以取別的名字)
  • Vite 會根據 template(模板)產生基本的 React 項目。

2. 安裝 npm 依賴項目:

1
2
3
$ cd frontend #進入React框架資料夾
$ npm instal # 使用npm安裝依賴項目
$ npm run dev # 開啟服務器

更多內容可以參考:Vite 官方文檔

3. 完成 React 安裝:

照著指示開啟網址http://localhost:5173/,沒意外的話就會看到以下畫面,React 基礎的安裝就完成了。

建立 Django 專案

1. 專案資料夾內使用終端機執行:

1
$ pip install django djangorestframework django-cors-headers

此指令使用 pip 安裝了三個套件:

  • Django:後端網頁框架
  • Django REST framework:用於建立 API 的擴充套件
  • Django CORS headers:用於處理 CORS 跨域請求問題,讓 API 安全地可以被不同的網頁訪問。

2. 調整專案架構:

1
2
3
4
5
6
$ django-admin startproject core # 使用django安裝專案
$ mv core backend # 將外層的core改名為backend
$ cd backend # 進入後端資料夾
$ poetry init --no-interaction --dependency django # 使用後湍套件管理工具
$ touch [README.md](http://README.md) #新增專案說明檔案(非必要)
$ poetry install # 安裝依賴套件

完成以上步驟就可以使用文字編輯器開啟專案啦( ੭ ˙ᗜ˙ )੭

另外可以在 poetry 管理套件的檔案:pyproject.toml加上package-mode = false
因為 poetry 會協助建立虛擬環境,所以往後在專案內的終端機要下指令時都要記得使用$ poetry shell

這時候可以看到目前專案結構:

3. 進行資料 migrate

  • 跑資料庫遷移 :$ python manage.py migrate
  • 開啟伺服器:$ python manage.py runserver

這裡使用 Django 內建的 SQLite,也可以使用自己喜歡的資料庫(在 GitHub 我後來有改用 PostgreSQL 才上傳)

4.建立 superuser & App

  • 建立管理員,方便進入 Django 內建後台: python manage.py createsuperuser
  • 建立一個名為 Word 的 APP:python manage.py startapp word

這時候基礎的 Django 就安裝完成了,不過還需要設定 API,才能搭起前端和後端的橋樑 ( ˶’ᵕ’˶)

設定後端 API & APP

基本上這裡的步驟都會是在 backend 資料夾內設定

1. Django 的環境設置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# backend.core.setting
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', #REST framework
'corsheaders', # CORS headers
'words' #APP
]

CORS_ALLOW_ORIGINS = ['http://localhost:5173'] #讓django可以接受這個react打過來的api,亦可使用ENV代入

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', # 建立session的middleware
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

這部的目的是將剛剛安裝的擴充工具、APP 都讓 Django 知道,並設定 CORS 來源網址。

新建 word model

1
2
3
4
5
6
7
# backend.words.models
from django.db import models

class Word(models.Model):
word = models.CharField(max_length=200, unique=True)
pronunciation = models.CharField(max_length=100)

新增 word model,使用這個是因為我想做一個單字卡網站,先使用最簡單的定義,你也可以使用任何您要 model 架構。

註冊 admin.py

1
2
3
4
from django.contrib import admin
from .models import Word

admin.site.register(Word)

讓剛剛創的 model 能出現在 admin 內,這步驟非必要,主要是新增資料而已,也可以使用 Django 的 ORM 新增資料,我自己覺得內建的 admin 蠻方便的所以先新增。

設定 Django REST framework

1. words 內新增 api 資料夾

新增serializers.pyurls.pyviews.py這三個檔案:

2. 序列化器(serializers)

這一步是 Django REST Framework(DRF)中非常重要的功能。
序列化器(serializers)負責將數據轉換成其他格式來傳輸,例如我們常用的 JSON 格式。
它同時還能處理數據的驗證和「反序列化」(即接收 JSON 資料並轉換成 Django 的資料庫模型物件),讓建立 API 的過程更加簡單。

簡單來說,序列化器就像是「翻譯」,它幫助使用不同語言的前端和後端進行溝通。

1
2
3
4
5
6
7
8
9
# backend.words.api.serializers.py

from rest_framework.serializers import ModelSerializer
from ..models import Word

class WordSerializer(ModelSerializer):
class Meta:
model = Word
fields = ['id', 'word', 'pronunciation']
  • ModelSerializer :這是幫助將 Django 模型轉換為 API 格式的工具。
  • class WordSerializer(ModelSerializer) : 定義了一個名為 WordSerializer 的序列化器的 class
  • fields = ['id', 'word', 'pronunciation']:當我們使用 WordSerializerWord 模型的資料轉換為 JSON 時,輸出內容會包含這三個欄位。反過來,把 JSON 資料轉換回 Django 物件時,也只會處理這些欄位。如果你想處理所有欄位,也可以寫成:fields = '__all__'

3. 設定 WordViewSet,並指定 WordSerializer

1
2
3
4
5
6
7
8
# backend.words.api.views.py
from rest_framework.viewsets import ModelViewSet
from ..models import Word
from .serializers import WordSerializer

class WordViewSet(ModelViewSet):
queryset = Word.objects.all() # 取得所有 Word 模型的資料
serializer_class = WordSerializer # 指定使用 WordSerializer
  • ModelViewSet:顧名思義,這是「視圖的集合」,專門用來幫我們處理視圖邏輯的。這是 DRF 內建的功能,能自動幫你搞定常見的 CRUD 操作。
  • WordViewSet:這是自定義的視圖集,專門負責處理 Word 模型的 API 請求。無論是查資料還是新增修改,它都能處理!
  • serializer_class = WordSerializer:這裡指定了序列化器,我們用剛剛創建的 WordSerializer 來處理資料的轉換和驗證,確保數據格式正確 (•̀ᴗ•́)و。

總結一下,這段程式碼幫我們自動建立了一個可以處理 Word 模型資料的 API。你只需要發送請求,就能輕鬆完成查詢、新增、修改和刪除資料的操作,真是省時又省力!ヽ(✿ ゚ ▽ ゚)ノ

4. 設定 URLS 路徑

在這個步驟中,我們將會透過 Django REST Framework 的 Routers 來輕鬆管理 URL,讓不同的 API 請求可以正確導向相應的處理邏輯。

4-1 api.urls.py:

首先,我們會在 words 相關的資料夾中新增一個 urls.py 檔案,並註冊 WordViewSet 路由:

1
2
3
4
5
6
7
# backend.words.api.urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import WordViewSet

word_router = DefaultRouter()
word_router.register(r'words', WordViewSet)
  • DefaultRouter():這是 Django REST Framework 提供的預設 Routers,它會幫你自動生成常用的 API 路徑,像是 GET /words/POST /words/等。
  • register():這裡我們將 WordViewSet 註冊到 Routers,讓 /words/ 路徑和 WordViewSet 連結在一起。

4-2 core.api.urls.py

接著,我們在 core 資料夾裡新增一個 api 資料夾,並在裡面新增一個 urls.py 檔案。
這一步的重點是將之前設定好的 words 路徑整合起來,讓所有的 API 路徑都統一由這個 urls.py 來管理。

這裡就像是 API 路徑的「部門經理」,所有的 API URL 都要交給它來發號施令~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# backend.core.api.urls.py
from rest_framework.routers import DefaultRouter
from words.api.urls import word_router
from django.urls import path, include

router = DefaultRouter()

# words
router.registry.extend(word_router.registry)

# 定義主要的 API URL 路徑
urlpatterns = [
path('', include(router.urls)),
]
  • router.registry.extend():這行程式把之前在 words.api.urls.py 裡設定好的 Router 也「報到」給部門經理,讓 /words/ 路徑與其他 API 一起被管理 (。•̀ᴗ-)✧,就像是新員工報到一樣,讓部門經理知道有這個路徑在。
  • path('', include(router.urls)):這行定義了進入 API 的主要路徑。當有人來訪問這個網址時,部門經理會把任務交給相應的主管 router,讓它去發號施令。

4.4 core.urls.py

這部分應該不難理解,主要是設定 API 的主要路徑。就像是 API 部門的經理跟 URL 的總經理報告:「我們的 API 部門已經建置完成,可以正式開始運作啦!」 (๑•̀ㅂ•́)و✧

1
2
3
4
5
6
7
8
# backend.core.urls.pu
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('core.api.urls')),
]

5. 執行 migrate 並啟動伺服器

1
2
3
python manage.py makemigrations
python manage.py migrate
python manage.py runserver

經過以上步驟,我們的後端 API 介面終於建置完成啦!🎉
打開瀏覽器,輸入 https://127.0.0.1:8000/api/words,你就能看到 API 介面!
在這裡,你可以直接新增資料,或者查看從後台 Admin 新增的 Word 資料。

這代表後端的 API 已經正式建置完成,前端也可以透過這個 API 來獲取資料啦!(๑•̀ㅂ•́)و✧

設定 React 環境

  • 這裡的動作都會在frontend 進行

1. 在 frontend 資料夾新增 .env 檔案

首先,我們要在 frontend 資料夾裡新增一個 .env 檔案,裡面設定 API 的網址,這樣之後我們在程式碼裡就可以透過環境變數來讀取 API 路徑了:

1
VITE_API_URL=http://localhost:8000/api/

2. 測試環境變數

接下來,我們要確認環境變數是否設置成功。在 src/app.jsx 裡新增以下代碼,然後在瀏覽器的控制台中看看結果吧!✨

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# src.app.jsx
import { useState, useEffect } from 'react'

function App() {

useEffect(() => {
console.log(import.meta.env.VITE_API_URL)
}, [])

return (
<div>
<h1>Hello World</h1>
</div>
)
}

export default App

瀏覽器打開後,如果控制台成功輸出我們剛剛在 .env 檔案裡設定的 API URL,那就代表環境變數設置成功啦!٩(◕‿◕。)۶

3. 從 API 抓取資料

現在,我們來讓 React 從 API 抓取資料,並在網頁上顯示結果。以下是更新後的 App 元件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# src.app.jsx

import { useState, useEffect } from 'react'

function App() {
const [data, setData] = useState([])

useEffect(() => {
async function fetchData() {
try {
const response = await fetch(`${import.meta.env.VITE_API_URL}/words/`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setData(data);
console.log(data)
} catch (error) {
console.error('Error fetching data:', error);
}
}
fetchData();
}, [])

return (
<div>
<h1>Hello World</h1>
{data.map((word) => (
<div key={word.id}>
<h2>{word.word}</h2>
<p>{word.pronunciation}</p>
</div>
))}
</div>
)
}

export default App

在這段程式碼中:

  • 我們用 useState 來存放從 API 取得的資料。
  • 使用 useEffect 來在元件載入時抓取 API 資料,並將資料顯示在畫面上。
  • 每個單字會顯示其 wordpronunciation

這樣一來,我們就能從後端 API 拿到資料並在前端網頁上動態顯示啦!ヾ(^ ∇ ^)

本篇文章是我由以下參考資料整理而成,如果您有興趣了解更多,請參考:

參考資料:

Comments