Django 專案結構與 MTV 架構模式 | Django 教學
理解 Django 的專案結構是高效開發的第一步。Django 採用獨特的 MTV(Model-Template-View)架構模式,將資料處理、頁面呈現與業務邏輯清楚分離。同時,Django 以 Project(專案)與 App(應用)的階層式組織來管理程式碼,讓每個功能模組都能獨立開發、測試與重複使用。本篇將帶你完整剖析 Django 的目錄結構與 MTV 架構,幫助你建立紮實的開發基礎。
MTV 架構模式詳解
MTV 是 Django 的核心設計模式,分別代表 Model(模型)、Template(模板)和 View(視圖)。這三個元件各司其職,構成了 Django 處理 Web 請求的完整流程。
Model(模型):資料層
Model 負責定義資料結構並處理與資料庫(Database)的互動。每個 Model 對應資料庫中的一張資料表(Table),透過 Django 內建的 ORM(Object-Relational Mapping,物件關聯對映)系統,開發者可以用 Python 程式碼操作資料庫,而不需要撰寫原始的 SQL 語句。
# models.py - 定義文章的資料模型
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200) # 文章標題
content = models.TextField() # 文章內容
created_at = models.DateTimeField(auto_now_add=True) # 建立時間(自動填入)
updated_at = models.DateTimeField(auto_now=True) # 更新時間(自動更新)
def __str__(self):
return self.title
Template(模板):呈現層
Template 負責決定資料如何呈現給使用者。Django 的模板系統(Template Engine)使用 HTML 搭配模板標籤(Template Tags)和過濾器(Filters),將 View 傳遞過來的資料渲染成最終的 HTML 頁面。
<!-- templates/articles/list.html -->
{% extends "base.html" %}
{% block content %}
<h1>文章列表</h1>
{% for article in articles %}
<div class="article">
<h2>{{ article.title }}</h2>
<p>{{ article.content|truncatewords:30 }}</p>
<span>{{ article.created_at|date:"Y-m-d" }}</span>
</div>
{% empty %}
<p>目前沒有任何文章。</p>
{% endfor %}
{% endblock %}
View(視圖):邏輯層
View 是 MTV 的核心樞紐,負責接收 HTTP 請求、執行業務邏輯、呼叫 Model 取得資料,再將資料傳遞給 Template 進行渲染,最後回傳 HTTP 回應(Response)。
# views.py - 處理文章列表的請求邏輯
from django.shortcuts import render
from .models import Article
def article_list(request):
articles = Article.objects.all().order_by('-created_at') # 從 Model 取得所有文章
return render(request, 'articles/list.html', { # 將資料傳給 Template 渲染
'articles': articles,
})
MTV 的請求處理流程
當使用者發出一個 HTTP 請求時,Django 的處理流程如下:
使用者發出 HTTP 請求
↓
URL 路由(urls.py)匹配對應的 View
↓
View 接收請求,執行業務邏輯
↓
View 透過 Model 操作資料庫(如有需要)
↓
View 將資料傳遞給 Template 渲染頁面
↓
回傳 HTTP 回應給使用者
MTV vs MVC 對比
如果你接觸過其他 Web 框架(如 Ruby on Rails、Spring MVC、ASP.NET MVC),一定對 MVC(Model-View-Controller)模式不陌生。Django 的 MTV 本質上是 MVC 的變體,只是命名不同:
| MTV(Django) | MVC(傳統) | 職責說明 |
|---|---|---|
| Model | Model | 資料結構定義與資料庫操作 |
| Template | View | 負責 HTML 頁面的渲染與呈現 |
| View | Controller | 處理請求邏輯、協調 Model 與 Template |
為什麼 Django 不直接叫 MVC?Django 的設計哲學認為,View 應該描述「使用者看到什麼資料」而非「資料長什麼樣子」,所以將呈現層命名為 Template,而將邏輯層命名為 View。至於 Controller 的角色,則由 Django 框架本身(特別是 URL 路由系統)來承擔。
Django 專案(Project)vs 應用(App)
在 Django 的世界裡,Project(專案)和 App(應用)是兩個層級不同的組織概念:
- Project:代表整個網站或 Web 應用程式,是所有設定與配置的中心。一個 Project 包含全域設定檔(
settings.py)、根層路由(urls.py)以及部署入口(wsgi.py、asgi.py)。 - App:代表一個獨立的功能模組,負責特定的業務領域。例如
usersApp 處理使用者註冊與認證、articlesApp 處理文章的 CRUD(建立、讀取、更新、刪除)操作。
一個 Project 通常包含多個 App,而一個設計良好的 App 可以在不同的 Project 中重複使用。這種模組化的設計正是 Django 強調的 DRY(Don’t Repeat Yourself,不重複自己)原則的體現。
專案目錄結構詳解
當你使用 django-admin startproject myproject 建立一個新專案時,Django 會自動生成以下目錄結構:
myproject/ # 根目錄
├── manage.py # 管理指令入口
└── myproject/ # Project 配置套件(與專案同名)
├── __init__.py # 標記此目錄為 Python 套件
├── settings.py # 專案核心設定檔
├── urls.py # 根層 URL 路由設定
├── wsgi.py # WSGI 部署入口
└── asgi.py # ASGI 部署入口
接下來逐一介紹每個檔案的角色。
manage.py:管理指令入口
manage.py 是 Django 專案的命令列工具,你在開發過程中幾乎所有的操作都會透過它來執行。它的作用等同於 django-admin,但已經預設綁定了當前專案的 settings 模組。
常用指令一覽:
# 啟動開發伺服器(預設 port 8000)
python manage.py runserver
# 建立資料庫遷移檔
python manage.py makemigrations
# 執行資料庫遷移
python manage.py migrate
# 建立超級使用者(管理員帳號)
python manage.py createsuperuser
# 開啟 Django 互動式 Shell
python manage.py shell
# 建立新的 App
python manage.py startapp blog
settings.py:核心設定檔
settings.py 是 Django 專案的「大腦」,集中管理所有設定。以下是幾個最重要的設定項:
# settings.py 關鍵設定項目
# 安全金鑰,用於加密簽名(正式環境務必保密)
SECRET_KEY = 'your-secret-key-here'
# 除錯模式(正式環境必須設為 False)
DEBUG = True
# 允許存取的主機名稱
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
# 已安裝的 App 清單
INSTALLED_APPS = [
'django.contrib.admin', # 後台管理介面
'django.contrib.auth', # 認證系統
'django.contrib.contenttypes', # 內容類型框架
'django.contrib.sessions', # Session 管理
'django.contrib.messages', # 訊息框架
'django.contrib.staticfiles', # 靜態檔案管理
]
# 中介軟體清單(依序執行)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 根層 URL 路由模組
ROOT_URLCONF = 'myproject.urls'
# 資料庫設定(預設使用 SQLite)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
urls.py:路由設定
urls.py 定義了 URL 與 View 的對應關係。Django 透過 URLconf(URL Configuration)系統,將使用者請求的 URL 路徑匹配到對應的 View 函式或類別。
# myproject/urls.py(根層路由)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls), # Django 內建後台管理
path('articles/', include('articles.urls')), # 將 articles/ 開頭的 URL 轉發給 articles App
path('users/', include('users.urls')), # 將 users/ 開頭的 URL 轉發給 users App
]
透過 include() 函式,每個 App 可以維護自己的 urls.py,實現路由的模組化管理。
wsgi.py:WSGI 入口點
WSGI(Web Server Gateway Interface,網頁伺服器閘道介面)是 Python Web 應用程式與 Web 伺服器之間的標準介面。wsgi.py 是 Django 在正式部署時的入口檔案,透過 Gunicorn 等 WSGI 伺服器來服務你的應用程式。
# wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_wsgi_application()
asgi.py:ASGI 入口點
ASGI(Asynchronous Server Gateway Interface,非同步伺服器閘道介面)是 WSGI 的進化版,自 Django 3.0 起內建支援。asgi.py 讓 Django 能夠處理非同步請求,支援 WebSocket、長輪詢(Long Polling)等即時通訊協定,透過 Uvicorn 或 Daphne 等 ASGI 伺服器部署。
# asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()
建立第一個 App
使用 startapp 指令來建立一個新的 App:
# 在專案根目錄下執行
python manage.py startapp blog
執行後,Django 會在專案根目錄下產生一個 blog/ 資料夾,其目錄結構如下:
blog/
├── __init__.py # 標記此目錄為 Python 套件
├── admin.py # 後台管理設定
├── apps.py # App 配置類別(AppConfig)
├── models.py # 資料模型定義
├── tests.py # 測試程式碼
├── views.py # 視圖函式或類別
└── migrations/ # 資料庫遷移檔案目錄
└── __init__.py
App 目錄結構詳解
models.py:資料模型
定義此 App 所需的資料結構。每個 class 對應一張資料庫表,Django ORM 會自動處理 SQL 的生成與執行。
views.py:視圖邏輯
撰寫處理 HTTP 請求的函式(Function-Based Views)或類別(Class-Based Views)。View 負責協調 Model 與 Template,是 MTV 架構的核心樞紐。
urls.py:App 層路由
Django 預設不會自動建立 App 層的 urls.py,需要手動新增。建議每個 App 都維護自己的路由,再透過根層 urls.py 的 include() 引入。
# blog/urls.py(手動建立)
from django.urls import path
from . import views
app_name = 'blog' # URL 命名空間,避免不同 App 之間的 URL 名稱衝突
urlpatterns = [
path('', views.article_list, name='list'),
path('<int:pk>/', views.article_detail, name='detail'),
]
admin.py:後台管理設定
在這裡註冊 Model,讓 Django 內建的 Admin(後台管理介面)能夠對該 Model 進行 CRUD 操作。
# blog/admin.py
from django.contrib import admin
from .models import Article
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'created_at', 'updated_at'] # 列表頁顯示的欄位
search_fields = ['title', 'content'] # 搜尋欄位
apps.py:App 配置
定義 App 的元資料,包括名稱與顯示名稱。ready() 方法可用於在 Django 啟動時執行初始化邏輯(例如連接 Signal)。
# blog/apps.py
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'blog'
verbose_name = '部落格管理' # 在 Admin 後台顯示的中文名稱
def ready(self):
import blog.signals # 載入 Signal 處理器(如有需要)
tests.py:測試程式碼
撰寫單元測試(Unit Test)和整合測試(Integration Test),確保 App 的功能正確無誤。
註冊 App 到 INSTALLED_APPS
建立 App 後,必須將它註冊到 settings.py 的 INSTALLED_APPS 中,Django 才會「認識」這個 App:
# settings.py
INSTALLED_APPS = [
# Django 內建 App
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 自訂 App(推薦使用 AppConfig 路徑)
'blog.apps.BlogConfig',
]
有兩種註冊方式:
- 簡寫:直接寫 App 名稱,例如
'blog' - 完整路徑(推薦):指向 AppConfig 類別,例如
'blog.apps.BlogConfig'
使用完整路徑的好處是可以在 apps.py 中自訂 verbose_name 和 ready() 方法,讓 Django 在啟動時自動載入相關配置。
未註冊到 INSTALLED_APPS 的 App,Django 不會載入其 Model、不會執行 Migrations、也不會在 Admin 後台中顯示。
WSGI vs ASGI 簡介
Django 提供了兩種部署協定入口,選擇哪一種取決於你的應用需求:
| 比較項目 | WSGI | ASGI |
|---|---|---|
| 全名 | Web Server Gateway Interface | Asynchronous Server Gateway Interface |
| 處理方式 | 同步(Synchronous) | 非同步(Asynchronous) |
| Django 支援版本 | 所有版本 | Django 3.0+ |
| 常用伺服器 | Gunicorn、uWSGI | Uvicorn、Daphne、Hypercorn |
| 適用場景 | 傳統 HTTP 請求/回應 | WebSocket、即時通訊、Server-Sent Events |
| 效能特性 | 每個請求佔用一個 Worker 執行緒 | 單執行緒可處理大量並發連線 |
對於大多數傳統的 Web 應用程式,WSGI 已經足夠應付。如果你的專案需要 WebSocket 或即時推播功能,則需要使用 ASGI。兩個入口可以在同一個專案中共存,你可以根據部署環境自由選擇。
部署指令範例:
# WSGI 部署(使用 Gunicorn)
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000
# ASGI 部署(使用 Uvicorn)
uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000
總結
本篇介紹了 Django 開發中最基礎也最重要的兩個概念:MTV 架構模式 與 專案目錄結構。
MTV 架構 將應用程式分為 Model(資料層)、Template(呈現層)和 View(邏輯層)三個清晰的職責區塊,讓程式碼的組織更有條理,也更容易維護與擴展。它與傳統 MVC 模式本質相同,只是 Django 選擇了更貼近 Web 開發直覺的命名方式。
專案結構 方面,Django 以 Project 為配置中心、App 為功能單元的階層式設計,讓開發者能夠將複雜的系統拆解為多個獨立的模組。每個 App 擁有自己的 Model、View、Template 和路由,可以獨立開發、測試,甚至跨專案重複使用。
掌握了這些基礎概念後,你就有了 Django 開發的「地圖」。在接下來的教學中,我們將深入每個元件,從 Model 的資料庫操作到 View 的請求處理,一步步帶你建構完整的 Web 應用程式。