2026年8月12日 星期三

用 Django 打造網站後台統計

網際網路應用實作教材

用 Django 打造網站後台統計

以「水井三寶」品牌網站為案例,從匿名訪客辨識、瀏覽事件、每日彙總,到 Django Admin 統計與 PythonAnywhere 部署,完成一套兼顧教學、實用與隱私的網站分析功能。

發表社群|智慧生活科技專業社群案例網站|水井三寶難度|入門至進階建議課時|3–4 小時

01 · Motivation網站上線之後,如何知道真的有人使用?

網站是否有人造訪,只看訂單或留言是不夠的。多數使用者會先閱讀故事、觀看影片、操作地圖,經過多次接觸後才採取行動。

水井三寶網站包含品牌故事、線上繪本、影音、互動地圖、編程任務與工藝商城。因此,除了「總瀏覽次數」,更需要知道使用者對哪種內容感興趣,以及教育活動是否真的被操作。

內容成效哪些故事、繪本和影片最常被閱讀或觀看?
教學互動哪些地圖景點被點選?編程任務是否完成?
轉換行為使用者是否加入購物車、送出訂單或聯絡訊息?
案例選擇:第一版採用 Django 自建統計,不依賴外部分析服務,適合 PythonAnywhere 免費方案與課堂示範,也能讓學生完整理解資料從瀏覽器進入資料庫的過程。

02 · Learning Goals本單元學習目標

  • 理解「瀏覽次數」與「不重複訪客」的差異。
  • 使用 Django Middleware 自動記錄公開頁面瀏覽。
  • 使用 JavaScript 與 Django 端點記錄影片、閱讀、地圖及任務事件。
  • 設計原始事件與每日彙總兩層資料模型。
  • 在 Django Admin 呈現期間統計、熱門頁面、篩選及 CSV 匯出。
  • 理解匿名化、資料最小化與保存期限等隱私原則。
  • 將功能部署到 PythonAnywhere 並完成測試。

03 · Architecture資料如何從網站走到管理後台?

使用者瀏覽器瀏覽、播放、翻頁、點選
DjangoMiddleware/事件端點
SQLite原始事件+每日彙總
Django Admin查詢、篩選、匯出

系統採用兩種蒐集方式:

1伺服器自動記錄每次成功開啟公開頁面時,由 Middleware 記錄 page_view
2前端互動記錄影片播放、繪本翻頁或地圖點選時,由 JavaScript 傳送事件。
3後端業務記錄加入購物車、完成訂購及送出聯絡表單時,直接由 Django View 寫入。

04 · Data Model設計原始事件與每日彙總

原始事件 AnalyticsEvent

每次操作保存一筆事件,方便日後回答「何時發生、發生在哪一頁、涉及哪一項內容」。

class AnalyticsEvent(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    event_type = models.CharField(max_length=32, choices=EVENT_CHOICES)
    path = models.CharField(max_length=500, blank=True, db_index=True)
    content_type = models.CharField(max_length=40, blank=True)
    content_id = models.CharField(max_length=80, blank=True)
    content_title = models.CharField(max_length=200, blank=True)
    visitor_hash = models.CharField(max_length=64, db_index=True)
    referrer_domain = models.CharField(max_length=255, blank=True)
    metadata = models.JSONField(default=dict, blank=True)

每日彙總 DailyAnalytics

同一天、同一事件與同一內容合併為一筆,保存操作次數與匿名訪客數。這能降低後台報表每次掃描大量原始事件的負擔。

class DailyAnalytics(models.Model):
    date = models.DateField(db_index=True)
    event_type = models.CharField(max_length=32, choices=EVENT_CHOICES)
    path = models.CharField(max_length=500, blank=True)
    content_type = models.CharField(max_length=40, blank=True)
    content_id = models.CharField(max_length=80, blank=True)
    total_count = models.PositiveIntegerField(default=0)
    unique_visitors = models.PositiveIntegerField(default=0)
指標意義例子
total_count事件總發生次數同一人看首頁 3 次,計為 3
unique_visitors不重複匿名訪客數同一人看首頁 3 次,計為 1
event_type使用者行為類別page_view、video_play、map_location

05 · Middleware自動記錄公開頁面瀏覽

Middleware 位於請求與回應的共同通道,適合處理每個頁面都需要執行的統計邏輯。只有 GET 且回應狀態為 200 的公開頁面才列入統計。

class AnalyticsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        prepare_visitor(request)
        response = self.get_response(request)

        should_track = (
            request.method == "GET"
            and response.status_code == 200
            and not request.path.startswith(EXCLUDED_PREFIXES)
            and not is_bot(request)
            and not request.user.is_staff
        )
        if should_track:
            record_event(request, "page_view")
        set_visitor_cookie(request, response)
        return response

settings.py 中,應放在 AuthenticationMiddleware 後方,才能辨識登入者是否為管理人員:

MIDDLEWARE = [
    # ...
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "website.middleware.AnalyticsMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
]
不要把所有請求都算成瀏覽:後台、圖片、CSS、JavaScript、影片、404 頁面及搜尋機器人都應排除,否則數據會被嚴重放大。

06 · Event Tracking不只看頁面,也記錄學習互動

事件觸發時機教學意義
reading_start進入線上讀物知道作品被開啟幾次
reading_page切換繪本頁面觀察閱讀進度
reading_complete抵達最後一頁估算完成閱讀人數
video_play/video_complete影片播放/播畢比較點閱與完播
map_location點選地圖景點辨識熱門文化景點
mission_start/mission_complete開始/完成編程任務評估教材使用情況
add_to_cart/order_complete購物流程觀察商品轉換

HTML 元件用 data-* 描述事件,不必在每個按鈕重寫一套程式:

<button
  data-analytics-event="map_location"
  data-content-type="map_location"
  data-content-id="{{ location.id }}"
  data-content-title="{{ location.name }}">
  {{ location.coordinate }}
</button>

JavaScript 透過同源 POST 傳送資料,並附上 CSRF Token:

sendAnalyticsEvent("video_play", {
  content_type: "video",
  content_id: video.dataset.contentId,
  content_title: video.dataset.contentTitle
});

伺服器端必須再次檢查事件白名單與欄位長度。前端送來的內容永遠不能直接信任。

07 · Admin Dashboard把資料變成可用的後台資訊

後台「每日流量統計」首頁提供三個時間範圍,以及最近 30 日熱門頁面:

今日掌握當日瀏覽次數與訪客數。
最近 7 日觀察活動或課程期間的短期變化。
最近 30 日比較內容的中期成效。

後台應具備的操作

  • 依日期、事件、內容類型篩選。
  • 搜尋頁面名稱、內容名稱及網址路徑。
  • 查看熱門頁面排行榜。
  • 選取資料並匯出 UTF-8 CSV,供 Excel 或研究報告使用。
  • 瀏覽原始事件以除錯,但不允許一般後台操作任意修改統計。
@admin.register(DailyAnalytics)
class DailyAnalyticsAdmin(admin.ModelAdmin):
    list_display = (
        "date", "event_type", "page_title",
        "content_title", "total_count", "unique_visitors"
    )
    list_filter = ("event_type", "date", "content_type")
    search_fields = ("page_title", "content_title", "path")
    actions = [export_as_csv]

08 · Privacy by Design統計功能也要尊重使用者

本案例不保存 IP 位址,也不建立姓名、Email 與瀏覽紀錄的關聯。瀏覽器只保存隨機識別碼,伺服器再以網站密鑰進行 SHA-256 雜湊。

visitor_hash = hashlib.sha256(
    f"{settings.SECRET_KEY}:{visitor_id}".encode("utf-8")
).hexdigest()
資料最小化只記錄回答教學與營運問題所需的欄位。
匿名處理不保存 IP,也不以統計資料辨識真實身分。
定期清理原始事件保留 180 日,每日彙總可長期保存。
python manage.py prune_analytics --days 180
網站公告建議:在隱私權政策中說明網站使用匿名 Cookie 進行流量與操作統計、使用目的、保存期間及聯絡方式。

09 · Deployment部署到 PythonAnywhere

將修訂檔上傳並解壓至專案根目錄後,在 Bash Console 執行:

cd /home/ShuijingTreasures/ShuijingTreasures
python manage.py migrate
python manage.py collectstatic --noinput
python manage.py check
python manage.py test

最後到 Web 頁面按下 Reload,再依序完成以下驗證:

  1. 用未登入的瀏覽器開啟首頁兩次。
  2. 登入 Django Admin,進入「每日流量統計」。
  3. 確認瀏覽次數為 2、訪客人數為 1。
  4. 播放影片、點選地圖景點,再確認對應事件。
  5. 管理者瀏覽後台或公開頁面時,不應增加統計。

10 · Classroom Practice課堂練習與延伸挑戰

練習一|判讀指標

某日首頁有 120 次瀏覽、45 位訪客;繪本有 60 次開始閱讀、18 次完成閱讀。請計算平均每位訪客瀏覽次數與閱讀完成率,並提出一項改善建議。

練習二|新增分享事件

新增 share_click 事件,在使用者按下社群分享按鈕時記錄分享平台及內容名稱。思考哪些 metadata 可以保存,哪些資料不應保存。

進階挑戰|完成率報表

在後台增加「繪本完成率」與「影片完播率」,並討論分母應使用事件次數還是不重複訪客數。

11 · Troubleshooting常見問題

後台完全沒有統計資料

確認已執行 migration、Middleware 已加入 settings、使用者不是後台管理員,且瀏覽器未送出 DNT(Do Not Track)。

影片播放沒有被記錄

確認新版 JavaScript 已執行 collectstatic、HTML 有 data-analytics-video,並在瀏覽器開發工具檢查事件 POST 是否回傳 200。

collectstatic 出現 PermissionError

chmod -R u+rwX static staticfiles
python manage.py collectstatic --noinput

訪客數看起來比預期多

使用者清除 Cookie、改用其他瀏覽器或裝置時,會被視為新的匿名訪客。此數字是近似值,不等同真實人數。

12 · Summary從「能上線」走向「能被理解」

網站開發不只是在頁面上呈現內容,也需要建立回饋循環:發布內容、觀察使用、分析結果,再改善設計與教材。

透過 Django Middleware、事件端點、每日彙總與 Admin 報表,水井三寶網站能在不保存 IP 的前提下,掌握文化內容、教育互動與商品流程的使用情況。這套案例同時串連 HTTP、Cookie、資料庫、JavaScript、後台管理、部署及資料倫理,是一個完整的網際網路課程實作單元。

DjangoPythonJavaScript網站分析PythonAnywhere資料隱私地方創生

智慧生活科技專業社群|網際網路課程教材

案例:水井三寶品牌網站「三寶同行・水井共生」

本教材可作為課堂示範、實作講義及專業社群文章使用。發布前請依實際課程補上作者、日期與授權方式。

沒有留言:

張貼留言