實戰背景
在大型 Python Django 專案中,網址路由(URL Routing)通常採用分布式定義。各個獨立的子應用(Apps)擁有自己的 urls.py,再透過主路由 urlpatterns 的 include() 進行層層嵌套。
痛點與問題描述:
我們需要重構電商後端的訂單付款接口,將原有的 GET /api/orders/<id>/pay/ 路由更名為 POST /api/orders/<id>/process-payment/,並改寫其對應的 View 視圖類別 OrderPaymentView。
由於 Django 的路由是基於正則表達式或 path 匹配的字串,傳統的 IDE 搜尋無法將「前端 AJAX 字串」與「後端的 views 實體」進行精確的強型別關聯。如果修改了後端 View 的方法,極易遺漏某個被 Django 內建模組引用的 URL 名稱(Named URLs)。因此,我們需要使用 OpenSpec 變更控制 與 Codegraph 來進行安全路由重構。
規格定義
本次變更計畫的 ID 為 django-route-refactor。我們在 OpenSpec 規格中定義了以下驗收標準:
# 實戰範例 001:openspec/changes/django-route-refactor/specs/django-router/spec.md
## ADDED/MODIFIED Requirements
### Requirement: Payment processing route definition
系統必須(SHALL)暴露 `POST /api/orders/<id>/process-payment/` 以處理訂單付款。
- 該路由必須(SHALL)與 `OrderPaymentView` 的 `post` 方法綁定。
- 原有的 `GET /api/orders/<id>/pay/` 必須(SHALL)被廢棄。
#### Scenario: Verify Django route execution
- **WHEN** 發送 HTTP POST 請求至 `/api/orders/42/process-payment/`
- **THEN** 系統必須(SHALL)成功調用 `OrderPaymentView` 並返回 JSON 格式的支付收據。
端到端 8 輪 AI 協作紀錄
以下是 You (開發者) 與 AI 助手在實施此重構時的完整對話歷史。
── 第 1 輪:探索 Django 路由定義 ──
- You:
/opsx:explore "我需要重構 orders 相關的 Django 路由。請用 codegraph explore 尋找 urls.py 檔案及其內部的 urlpatterns 定義。" - AI:
好的,已進入探索模式。我將呼叫
codegraph_explore尋找專案中定義了urls.py的位置,以確認訂單路由的根入口。CG 呼叫:
codegraph_explore(symbol: "urls.py")
CG 回傳:- 路徑:
shop/urls.py(主路由) 與shop/orders/urls.py(訂單子路由)。
接下來,我讀取
shop/orders/urls.py的原始碼以檢視訂單路由配置。CG 呼叫:
codegraph_explore(symbol: "shop/orders/urls.py")
CG 回傳:- 原始碼:
from django.urls import path from .views import OrderPaymentView urlpatterns = [ path('<int:id>/pay/', OrderPaymentView.as_view(), name='order-pay'), ]
分析:
訂單付款路由確實被定義為<int:id>/pay/,並與OrderPaymentView視圖綁定,且命名為'order-pay'。接下來我們需要查看OrderPaymentView的實作。 - 路徑:
── 第 2 輪:查看 View 實作 ──
- You:
使用 codegraph explore 讀取 OrderPaymentView 的 views.py 代碼。 - AI:
我呼叫
codegraph_explore檢索該 View 類別的原始碼。CG 呼叫:
codegraph_explore(symbol: "class OrderPaymentView")
CG 回傳:- 檔案路徑:
shop/orders/views.py - 原始碼:
from django.views import View from django.http import JsonResponse class OrderPaymentView(View): def get(self, request, id): # 舊的 GET 支付邏輯,安全隱患:GET 不應修改伺服器狀態 return JsonResponse({"status": "processing", "order_id": id})
分析:
該 View 目前僅實作了get方法。依據安全規範,變更伺服器狀態(進行扣款)必須改用post方法。因此重構方案需要將get重構為post。 接下來,我們需要確認這個order-payURL 命名在整個系統中被哪些上游視圖或模板引用。 - 檔案路徑:
── 第 3 輪:檢索 URL 命名引用 ──
- You:
使用 codegraph explore 檢索引用了 'order-pay' 或 reverse('order-pay') 的代碼位置。 - AI:
好的,我將呼叫
codegraph_explore搜尋專案中引用了'order-pay'的 Inbound Callers。CG 呼叫:
codegraph_explore(symbol: "order-pay")
CG 回傳:- Inbound Callers:
shop/orders/templates/order_detail.html(第 34 行):{% url 'order-pay' order.id %}shop/orders/tests.py(第 12 行):reverse('order-pay', args=[1])
分析:
我們找到了兩個依賴端:- HTML 模板:
/shop/orders/templates/order_detail.html中的按鈕超連結。 - 測試:
/shop/orders/tests.py中的 API 測試。
我現在退出探索模式,為您建立變更計畫。
- Inbound Callers:
── 第 4 輪:建立提案 ──
- You:
/opsx:propose "將 Django 訂單支付 API 從 GET/pay 重構為 POST/process-payment,修改 View 視圖並同步更新 Named URL 與測試" - AI:
好的,提案
django-route-refactor已建立!- proposal.md: 說明將支付方法改為 POST 並更新路由的安全性考量。
- specs/django-router/spec.md: 定義 HTTP POST 與 JSON 收據驗收標準。
- tasks.md: 任務拆解:
- 1.1 修改
shop/orders/urls.py將路由改為process-payment/,Named URL 改為order-process-payment。 - 1.2 重構
views.py的OrderPaymentView實作post方法。 - 1.3 更新 HTML 模板中的 url 名稱,並將點擊事件改為發送 POST 請求。
- 1.4 更新
tests.py並執行測試。
- 1.1 修改
請輸入
/opsx:apply開始實作。
── 第 5 輪:修改路由定義 (Task 1.1) ──
- You:
/opsx:apply - AI:
Implementing: django-route-refactor (schema: spec-driven)
正在處理任務 1.1:修改
urls.py路由。我已更新了
shop/orders/urls.py,更改為:urlpatterns = [ path('<int:id>/process-payment/', OrderPaymentView.as_view(), name='order-process-payment'), ]✓ 任務 1.1 完成!已在
tasks.md中勾選。
── 第 6 輪:重構 View 實作 (Task 1.2) ──
- You:
繼續任務 1.2,重構 views.py,改用 post 方法接收。 - AI:
Implementing: django-route-refactor
正在處理任務 1.2:重構
views.py。我將
OrderPaymentView中的get刪除,改為post實作扣款邏輯:class OrderPaymentView(View): def post(self, request, id): # 執行付款邏輯 return JsonResponse({"status": "success", "order_id": id, "tx_id": "tx_abc123"})✓ 任務 1.2 完成!
── 第 7 輪:更新模板與測試並驗證 ──
- You:
繼續實作任務 1.3 與 1.4,更新 HTML 模板與測試並進行驗證。 - AI:
Implementing: django-route-refactor
正在處理任務 1.3 & 1.4:模板/測試更新與全域驗證。
- HTML 模板:已將
order_detail.html的按鈕更改為 AJAX POST 提交,指向{% url 'order-process-payment' order.id %}。 - 測試代碼:已將
tests.py中的self.client.get改為self.client.post(reverse('order-process-payment', args=[42]))。 - 測試執行:執行
python manage.py test,測試全數通過!
已將變更合併至主規格並歸檔。
Archive Complete
變更計畫已成功歸檔!
- HTML 模板:已將
── 第 8 輪:重構價值總結 ──
- You:
總結本次利用 Codegraph 重構 Django 路由的優點。 - AI:
透過 Codegraph 的框架路由感知,我們實現了:
- 字串依賴精確檢索:Django 模板中的
{% url 'name' %}與 Python 的reverse('name')在傳統 IDE 中只是個字串。Codegraph 能感知 Named URLs,在inboundCallers中精確列出這兩個引用點,確保沒有任何遺漏。 - 安全升級:將危險的 GET 修改請求重構為規範的 POST,提升了系統的安全性。
- 字串依賴精確檢索:Django 模板中的