2026年2月18日 星期三

[Django 6.0] 佈署Django到Render平台

1. 安裝虛擬環境工具
pip install virtualenvwrapper-win


2.建立虛擬環境

mkvirtualenv django_env

執行後畫面


環境都存在哪裡?

預設位置:

C:\Users\你的帳號\Envs


3.熟悉虛擬環境的指令

python --version → 確認是乾淨環境

deactivate → 離開

lsvirtualenv 或 workon → 看到 testenv 了嗎?

workon testenv → 再切回去


4.安裝Django

pip install django


5.製作安裝套件的文件requirements.txt

pip freeze > requirements.txt


6.初始化mysite Django 專案

django-admin startproject mysite


7.更換工作目錄
cd mysite

8.執行本地端網站
python manage.py runserver


9.打開瀏覽器
http://127.0.0.1:8000/

10.建立一個新應用程式

python manage.py startapp myapp


11.添加應用程式,mysite/mysite/settings.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Django settings for mysite project.

Generated by 'django-admin startproject' using Django 6.0.2.

For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-!mi(werx6fq32e)h4we%q(d5k=(=coxpx^ux9z!#pqv=*-il13'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
]

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',
]

ROOT_URLCONF = 'mysite.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'mysite.wsgi.application'


# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases

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


# Password validation
# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/

STATIC_URL = 'static/'

12.建立網頁 mysite/templates/index.html 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Hello Django on Render!</title>

    <link rel="stylesheet"
          href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
          integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
          crossorigin="anonymous">
</head>
<body>
<main class="container">
    <div class="row text-center justify-content-center">
        <div class="col">
            <h1 class="display-4">Hello World!</h1>
        </div>
    </div>
</main>
</body>
</html>


13.建立一個簡單的視圖,mysite/myapp/views.py

1
2
3
4
5
from django.shortcuts import render


def index(request):
    return render(request, 'index.html', {})

14.設定路徑,mysite/mysite/uels.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
"""
URL configuration for mysite project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/6.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from myapp import views

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

15.重新啟動網站
python manage.py runserver

16.用render.yaml部署,放在mysite目錄下,和manage.py在同一個目錄。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
databases:
  - name: mysitedb          # 資料庫服務名稱(可自訂)
    plan: free              # free / starter 等,免費版夠用
    databaseName: mysite    # 資料庫名稱
    user: mysite            # 使用者名稱(Render 會自動產生密碼)

services:
  - type: web
    name: mysite            # Web Service 名稱
    env: python             # Python 環境
    plan: free              # 免費方案
    region: singapore       # 建議選離台灣近的(如 singapore 或 oregon),跟資料庫同區域避免延遲
    buildCommand: pip install -r requirements.txt && python manage.py collectstatic --noinput
    startCommand: gunicorn mysite.wsgi:application --bind 0.0.0.0:$PORT
    # 如果你的專案資料夾是 mysite/mysite(內層),startCommand 改成:gunicorn mysite.wsgi:application ...

    envVars:
      - key: PYTHON_VERSION
        value: 3.14.1           # 或你的 Python 版本
      - key: SECRET_KEY
        generateValue: true   # Render 自動產生安全的 SECRET_KEY
      - key: DEBUG
        value: "False"
      - key: DATABASE_URL
        fromDatabase:
          name: mysitedb      # 對應上面的資料庫 name
          property: connectionString  # 自動注入 postgresql://... 格式
      - key: ALLOWED_HOSTS
        value: "*"            # 測試用,之後改成你的域名

17.先把專案推到 GitHub
  • 如果還沒 repo:
git init
git add .
git commit -m "Initial commit"
  • 建立 GitHub repo(private 或 public 都行)
  • push:
git remote add origin https://github.com/你的帳號/你的專案.git
git branch -M main
git push -u origin main

18.建立新的藍圖
https://dashboard.render.com/blueprints


19.選擇包含您的藍圖的儲存庫,然後按一下「連線」。


20.命名後,按下部署鍵

21.部署過程,顯示:ModuleNotFoundError: No module named 'app'
在 Render Dashboard 修正 Start Command 登入 https://dashboard.render.com → 選你的 Web Service(mysite) 點 Settings(或 Edit) 找到 Start Command 欄位 改成:gunicorn mysite.wsgi:application

22.再度部署,部署成功後,瀏覽器訪問時,收到 400 Bad Request
127.0.0.1 - - [18/Feb/2026:08:20:57 +0000] "HEAD / HTTP/1.1" 400 143 ... 127.0.0.1 - - [18/Feb/2026:08:21:01 +0000] "GET / HTTP/1.1" 400 143 ...
這不是 Gunicorn 或 port 綁定問題,而是 Django 的安全檢查 觸發:你的 ALLOWED_HOSTS 設定沒包含 Render 給的域名(這裡是 mysite-1-p20l.onrender.com)。
Django 在 production 模式(DEBUG=False)下,會嚴格驗證 Host header。如果 Host 不匹配 ALLOWED_HOSTS,就直接回 400 Bad Request(不會給詳細錯誤頁面)。

23.修改mysite/mysite/setting.py
ALLOWED_HOSTS = [
    'mysite-1-p20l.onrender.com',   # 你的實際 Render URL(從 log 抄)
    '.onrender.com',                 # 萬用(wildcard),涵蓋所有子域名,測試超方便
    'localhost',                     # 本地開發用,可選
    '127.0.0.1',
]

24.重新把修改後的程式,上傳到Github
git add mysite/settings.py
git commit -m "Fix ALLOWED_HOSTS for Render deployment"
git push origin main

25.自動重新部署
Render 會自動偵測 push → 自動 redeploy(如果開了 auto-deploy)
也可以用手動 redeploy(如果等不及)
去 Render Dashboard → 你的服務(mysite-1-p20l)→ Manual Deploy → Deploy latest commit

26.開啟網站



沒有留言:

張貼留言