Django 專案結構與 MTV 架構模式 | Django 教學

2026/05/25 2026/05/21
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.pyasgi.py)。
  • App:代表一個獨立的功能模組,負責特定的業務領域。例如 users App 處理使用者註冊與認證、articles App 處理文章的 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)等即時通訊協定,透過 UvicornDaphne 等 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.pyinclude() 引入。

# 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.pyINSTALLED_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',
]

有兩種註冊方式:

  1. 簡寫:直接寫 App 名稱,例如 'blog'
  2. 完整路徑(推薦):指向 AppConfig 類別,例如 'blog.apps.BlogConfig'

使用完整路徑的好處是可以在 apps.py 中自訂 verbose_nameready() 方法,讓 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 應用程式。

BenZ Software Developer

熱愛技術的軟體開發者,在這裡分享程式開發經驗與學習筆記。