1. 程式人生 > 其它 >使用 React 和 Django REST Framework 構建你的網站

使用 React 和 Django REST Framework 構建你的網站

在我們最近的工作中,構建網站使用的架構是帶有 Django REST Framework(DRF)後端的 React 前端。它們是通過在前端使用 axios(前端庫)呼叫後端 API 來互動的。我們還使用了 Redux(前端庫)來儲存全域性的應用程式狀態(存在瀏覽器端)。這是我們首選,因為它允許前後端完全分離。只要我們提前定義好請求的資源列表(後面單個都簡稱:endpoint)和返回的資料格式,前端和後端就可以並行的進行開發。這也使我們可以輕鬆的為未來的任何專案建立移動端 App,因為它們仍然可以複用後端 API。

在本文的剩餘部分,我將介紹如何配置 React 前端和 DRF 後端。注意我假設你已經熟悉了 React,Redux,Django,DRF,NPM 等,本篇不是基礎教程哦。


後端(The Backend)

除了簡單安裝 Django 和 DRF 以及設定資料庫以外,後端沒有太多的工作要做

$ pip3 install django djangorestframework django-filter
$ pip3 freeze > requirements.txt

沒錯我們用的是 Python3

找一個目錄,建立一個 Django 專案和 Django App:

$ django-admin startproject backend
$ cd backend
$ django-admin startapp api

接下來應該配置好你的資料庫並編輯你的專案 settings 檔案來使用它。在 Django 的官網上可以找到關於如何為你的特定 DB 執行此操作的文件。

或者你也可以什麼都不幹,它會幫你在專案跟目錄建立一個檔案資料庫:sqlite3.db

最後你還應該按照在這裡的說明配置一下 DRF。

有些同學對前後端分離的認證方式有些懵逼,我們下面就看一下前後端分離的架構如何配置認證後端:

# file: api/urls.py
from django.conf.urls import url
from rest_framework.authtoken import views as drf_views

urlpatterns = [
    url(r'^auth$', drf_views.obtain_auth_token, name='auth'),]

只是為了確保清楚,你的 backend/urls.py 檔案現在應該是這樣:

# file: backend/urls.py
from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('api.urls', namespace='api', app_name='api')),]

通過這樣,我們可以讓每個應用程式管理自己的 URL。因為也許將來你會在後端新增更多的應用程式,並且將他們新增到 backend/urls.py。

現在,你已經擁有了一個後端 DRF API:叫 /auth 的 endpoint,訪問它可以獲得一個身份驗證令牌。讓我們先配置一個使用者,並執行後端伺服器以供測試。

$ python3 manage.py migrate
$ python3 manage.py createsuperuser
$ python3 manage.py runserver 0.0.0.0:8000

記得第一次要執行遷移命令(migrate)來建立你的資料庫。然後,我們建立一個使用者。在伺服器執行的情況下,你可以使用 curl 快速測試您的 /auth endpoint:

$ curl -X POST -d "username=username&password=password"
http://localhost:8000/auth

譯者在驗證過程中發現作者忽略了一些細節,補充如下

1.新增 rest_framework和rest_framework.authtoken 到 INSTALLED_APPS 配置:

# file: backend/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
]

2.執行命令建立認證 App 所需的資料庫:

$ python manage.py migrate

介面 I/O

到這裡,後端搞定


前端(The Frontend)

前端我們使用 Facebook 的 create-react-app 腳手架作為 base。首先要做的就是安裝它,然後在專案資料夾的根目錄下使用它來建立一個新的專案。

$ npm install -g create-react-app
$ create-react-app frontend
$ cd frontend
$ yarn eject

提示:執行 yarn eject 之前必須要提交所有 git 修改,因為它會更改你的檔案和新增目錄,怕你丟失之前的修改

接下來我們安裝一些依賴:

$ npm install --save-dev babel-preset-es2015 babel-preset-stage-3
$ npm install --save redux redux-logger redux-persist react-redux
$ npm install --save axios react-router-dom lodash

現在,我們先只展示將前端連線後端的主要部分。首先建立一個 redux store,用它來儲存使用者的 token,以便將來進行更多的API呼叫。

// file: src/store.js
import { compose, createStore, applyMiddleware } from 'redux';
import { createLogger } from 'redux-logger';
import { persistStore, autoRehydrate } from 'redux-persist';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  compose(
    applyMiddleware(
      createLogger(),
    ),
    autoRehydrate()
  ));persistStore(store);
export default store;

然後配置 token 的 reducer:

// file: src/reducers/index.js
import { combineReducers } from 'redux';
import * as actionType from '../actions/types';

const tokenInitialState = null;
const token = (state = tokenInitialState, action) => {
  switch(action.type) {
    case actionType.SET_TOKEN:
      return action.data;
    default:
      return state;
  }
}

const appReducer = combineReducers({
  token,
})

const rootReducer = (state, action) => {
  return appReducer(state, action);
}

export default rootReducer;

最後是配置 action(注意程式碼塊有兩個不同的檔案)

// file: src/actions/index.js
import * as actionType from './types';

export const setToken = (data) => {
  return {
    type: actionType.SET_TOKEN,
    data
  }
}

// file: src/actions/types.js
export const SET_TOKEN = "SET_TOKEN";

有了一個 action,我們現在可以在登入後 dispatch 使用者的 token 到 store 中。我們看看如何登入:

// file: src/util/Auth.js
import axios from 'axios';
import _ from 'lodash';
import store from '../store';
import { setToken } from '../actions';
import { URL, LOGIN } from '../config/Api';

export function InvalidCredentialsException(message) {
    this.message = message;
    this.name = 'InvalidCredentialsException';
}

export function login(username, password) {
  return axios.post(URL + LOGIN, {
      username,
      password
    })
    .then(function (response) {
      store.dispatch(setToken(response.data.token));
    })
    .catch(function (error) {
      // raise different exception if due to invalid credentials
      if (_.get(error, 'response.status') === 400) {
        throw new InvalidCredentialsException(error);
      }
      throw error;
    });
}

export function loggedIn() {
  return store.getState().token == null;
}

這段程式碼使用 axios POST 登入資訊到我們的 /auth endpoint,然後將返回的 token

dispatch 到我們的 redux store。一旦完成,我們就可以使用我們儲存的 token 令牌來建立一個基於 axios 的 API 客戶端(譯者注:這樣就不需要每次都顯式的將令牌資訊從 store 中拿出來再插入 payload 中了),這樣從我們的 React 元件中的其他地方進行其他 API 呼叫就很方便了。

// file: src/util/ApiClient.js
import axios from 'axios';
import store from '../store';
import { URL } from '../config/Api';

export const apiClient = function() {
    const token = store.getState().token;
    const params = {
        baseURL: URL,
        headers: {'Authorization': 'Token ' + token}
    };
    return axios.create(params);
}

前面的後兩個程式碼塊中我們引用瞭如下的 ../config/Api 檔案。它只是一個將常量對映到 endpoint 的檔案,它會使程式碼更易讀,更容易修改。(如果有些懵,可以參考譯者按照筆者的思路還原的程式碼,在文末)

export const URL = process.env.API_URL;
export const LOGIN = "/auth";

這就是一套連線我們的前端和後端的程式碼了。你現在可以嘗試使用 Auth.js 登入功能來獲取我們之前建立的使用者身份驗令牌。這樣可以通過從瀏覽器的開發者工具檢查 redux-logger 的輸出,來檢視 setToken redux 的 action 結果了。

目錄總覽

如果對一些細節不清楚,或者因為排版問題看不清,可以直接看原始碼:

https://github.com/tmpbook/django-with-vuejs/tree/master/examples/django-auth-with-react