Try   HackMD

網頁前後端程式設計 (2021.06.05)

後端理論 (以 Django 為例)

MVC architecture

MVC 是由三個字組成,分別為

Model
View
Controller

在後端裡面

Model: DB, DBMS, 操作 DB 的 algorithm, etc.

View: 在以前前後端混和的時代裡,view 代表 HTML 的 template。但是在前後端分離情況下,view 會到前端實作,所以,在後端就沒有 view 了

Controller: 使用者在前端會輸入一個 URL (http:////),此時,後端的 router 接收到 URL 之後,會解析這個 URL,交給對應的 controller 處理,controller 就要負責從 model 取出資料給前端,如果回傳資料量較大,則會需要套用模板回傳給前端。而在前後端分離的情況,後端就會使用 JSON 格式回傳資料

JSON (JavaScript Object Notation) 為將結構化資料 (structured data) 呈現為 JavaScript 物件的標準格式,常用於網站上的資料呈現、傳輸 (例如將資料從 server 送至 client 端,以利顯示網頁)。

簡單來說,JSON 就是一個 key 對應一個 value,例如

{ "firstName": "John", "lastName": "Smith", "sex": "male", "age": 25, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021" }, "phoneNumber": [ { "type": "home", "number": "212 555-1234" }, { "type": "fax", "number": "646 555-4567" } ] }

以上面為例,firstname 就是一個 key,其對應的 value 就是 John

JSON 的概念可以對應到 python 的 dictionary

MVC 在 Django 裡的概念

這點須特別注意,在 Django 裡
controller 叫做 view
view 叫做 template

Controller 的一些細節







details of controller



URL

URL



middleware

middleware



URL->middleware





Authentication

Authentication



middleware->Authentication





Authorization

Authorization



middleware->Authorization





Login

Login



Authentication->Login





Captcha

Captcha



Authentication->Captcha





Log

Log



Authentication->Log





controller

controller



Authorization->controller





Login->controller





Captcha->controller





Log->controller





Server 會記錄 Log,大致流程如下







log



Server

Server



Session

Session



Server->Session





cookie

cookie



Server->cookie





SessionID

SessionID



Session->SessionID





key

key



cookie->key





Authentication

Authentication



SessionID->Authentication





key->SessionID





Data

Data



Authentication->Data





Server 會創造一個 session,和一個 cookie 回傳給 client。當 client 要求資料的時候,server 會看這個 session ID 與 cookie 有沒有符合

Session 是一個很大的 Hashtable,裡面會存著每位 client 的 session ID,每個 session ID 就會記錄著 user ID, last login time, etc.

大概像這樣

{ "sujkfrukhfakhfukuahfl": { // session ID "uid": 0; "name": "otischung"; ... } }

在前後端分離的實作中,server 需要有一個 Authentication 的 model 處理 client 的驗證,client 使用 POST 對 server 發出 login 的請求,如果驗證成功,server 就會回傳 token,client 之後每次請求就要帶著這個 token 對於 server 發出請求,server 也會對於每次請求驗證 token 之後回應 client

後端實作 (Django) (使用 pycharm 開發)

安裝 Django 暨初始化專案

首先安裝 Django

pip install django

安裝完成之後,就會有 django-admin 這個指令,可以查看有哪些指令可用

接下來,我們就要使用 Django 開發後端

django-admin startproject <project_name> <location>

例如:

django-admin startproject tmp_project ./

這樣 Django 就會在這個這個目錄下新增目錄名為 tmp_project,並且會在專案目錄下新增 manage.py,之後我們會一直使用 manage.py 操作後端

我們可以用以下指令啟動後端

python manage.py runserver

此時會看到 server 運作在 http://127.0.0.1:8000/ 裡面,到瀏覽器輸入就能看到 Django 的 Hello World 畫面

Django 預設的管理介面

可以發現在 tmp_project 目錄下,有一個 urls.py,其中有一項

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

這是 Django 預設的管理介面,我們實際去 http://127.0.0.1:8000/admin/ ,就能看到 Django 的 admin 登入頁面

SQLite 與 Django 的關聯

在我們第一次 runserver 之後,就會在專案目錄下新增 db.sqlite3 的檔案,sqlite 會將 DB 存在一個檔案裡,所以不需要另外架設 SQL server

我們看一下 tmp_project 目錄下的 settings.py,會看到 Django 預設使用的 DB 是 SQLite3

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }

同步 DB 與 program: Migrate

一般來說,要架設一個 server,首先就是要安裝 server,create DB,然後在上述的地方輸入一些例如帳號密碼的驗證規則。再來就是要寫一些 SQL 的指令來保證 DB 的資料和程式上的資料是一致的,雖然比較麻煩,但是在一些大型專案,還是免不了人工設定

目前主流的 Relative Database 是 PostgreSQL,MySQL 已經有點過時了,

而 Django 有一個東西稱為 Migration,當你寫完 model 之後,migration 會自動產生 SQL 語句,讓 DB 的資料和程式上的資料是一致的,優點是很方便,缺點就是沒有彈性

執行以下指令

python manage.py makemigrations

第一次會顯示 No changes detected
之後如果有改到 models.py 的話,一定要記得執行以上指令

接著執行

python manage.py migrate

這樣就會把所有變更寫到 db.sqlite3 裡面

新增管理員

Django 的框架是自帶後台的,所以我們可以執行以下指令新增管理員

python manage.py createsuperuser

接著輸入帳號密碼,即設定完成,這樣我們就可以登入進去 http://127.0.0.1:8000/admin/ 裡面了

我們可以發現,Django 預設有 Groups 和 Users 這兩個 DB

後端新增功能 (留言板 comment)

後端的架構大致上是如下圖所示







details of controller



Site

Site



Application

Application



Site->Application





MVC

MVC



Application->MVC





所以,我們要新增一個 app 名為 comment

python manage.py startapp comment

我們就能看到 Django 為我們新增了名為 comment 的目錄,也在這個目錄底下新增了一些檔案

連結 DB models.py

這裡的寫法就是用 class 將 models 包進來

from django.contrib.auth.models import User from django.db import models # Create your models here. class Comment(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE) # ForeignKey: 關聯到另一張表; CASCADE: 連動刪除 created_at = models.DateTimeField(auto_now_add=True) content = models.TextField(max_length=300) def __str__(self): return f"{self.author.username}: {self.content[:20]}"

User

Django 裡有一個 field (model) 名為 User,將其 import 進來即可使用
User 裡面有一個 field 名為 Username

正規化 (Normalization) use ForeignKey

假設有一張表叫做 Comments,這張表有一個欄位叫做 Author,裡面會儲存很多關於這個 Author 的訊息。當我們想要存取、新增或修改 Author 裡的某一個訊息的時候,我們不希望走訪所有欄位 (linear search)

Comments

Author Sudoer Contents Write Time
Otis Chung yes text1, text2, t1, t2,
Ray Chung no text3, text4, t3, t4,
第一正規化 NF1

我們會將所有含多筆資料的欄位展開,使 key 與 value 形成 one-to-one 的形式;並且給 Author 這張表所有欄位一個 id 為主鍵值 (primary key),隱含著id為這張表中不可重複且具代表性的唯一

Comments

ID Author Sudoer Contents Write Time
1 Otis Chung yes text1 t1
2 Otis Chung yes text2 t2
3 Ray Chung no text3 t3
4 Ray Chung no text4 t4

如此一來,client 要查詢的時候,只需要輸入 ID 即可搜尋到想要的資料

第二正規化 NF2

隨著留言數越來越多,我們會發現為了製造 one-to-one 的形式,形成空間浪費

Comments

ID Author Sudoer Contents Write Time
1 Otis Chung yes text1 t1
2 Otis Chung yes text2 t2
3 Ray Chung no text3 t3
4 Ray Chung no text4 t4
5 Otis Chung yes text5 t5
6 Otis Chung yes text6 t6
7 Ray Chung no text7 t7
8 Ray Chung no text8 t8

所以,我們會將 Author 獨立出來建表,如此一來就能省下空間

Comments

ID Author_ID Contents Write Time
1 A1 text1 t1
2 A1 text2 t2
3 A2 text3 t3
4 A2 text4 t4
5 A1 text5 t5
6 A1 text6 t6
7 A2 text7 t7
8 A2 text8 t8

Author

Author_ID Author Sudoer
A1 Otis Chung yes
A2 Ray Chung no

如此一來,client 要查詢的時候,只需要輸入 Author_ID 和 ID 即可快速又簡單得搜尋到想要的資料

ForeignKey 的意思就是參考到另一張表

新增寫好的 app: comment

將寫好的 models 註冊到管理頁面
admin.py 裡面這樣寫

from django.contrib import admin from .models import Comment # Register your models here. admin.site.register(Comment)

在 tmp_project 裡面的 settings.py 裡面的 INSTALLED_APPS 加上我們所新增的 app: comment

INSTALLED_APPS = [ ..., 'comment' ]

記得,我們已經修改了 models.py,所以要重新 migrate

python manage.py makemigrations python manage.py migrate