Windows+Apache+Python+Django 踩坑記錄

i0發表於2019-07-26

摘要

  使用Python進行Web專案開發;相對於主流三大Web端解決方案(Java/.NET/PHP) Python在某些方面具有一定的優勢,相對 Java/.NET 有更輕量級的部署方案,相對PHP有更安全開放的環境支援,這些不同點幾乎完全取決於Python語言本身的特性。

0x01: 環境部署

  注:開發環境與執行環境的部署需要的基本技能 —— 理論基礎知識紮實,瞭解相關基本原理,瞭解具體開發體系;如果不具備這些能力那麼遇到問題就會很懵

  0x11: Windows+Apache 部署

  1. Apache壓縮包直接百度 "Apache" 就能找到官網下載了,飛機票>> Apache24 ;壓縮包解壓至安裝目錄,路徑最好不要含有中文和空格(江湖規矩)

  2. httpd.conf 配置檔案(apachePath/conf/httpd.conf),Apache部署中最重要的部分,一般只用修改第一條 ServerRoot 就可以了,文件中 "#" 為行註釋

    ServerRoot 改為你的真實路徑(一般在37行上下),Ex: ServerRoot "D:/Program/Apache/Apache24",新版本Apache中採用 "SRVROOT" 巨集替換後面所有會用到路徑的地方,新版本修改 Define SRVROOT "c:/Apache24" 為真實路徑可全域性替換,較老版本要手動修改以下兩個地方:標識靜態檔案路徑(大概在251行上下)以及檔案訪問許可權,CGI 指令碼路徑及訪問許可權(大概在368/380行上下);注意:路徑分隔為 "/" 而不是 "\"

    Listen 為監聽埠,預設80(通常在60行上下)一般不用修改

    LoadModule 為隨Apache啟動載入的模組(71-185左右),一般不用管

    ServerName 取消註釋(225上下),好像是 IANA DNS導航什麼的

    DocumentRoot 表示靜態檔案路徑,見第一條 ServerRoot

    ErrorLog 表示記錄檔案輸出路徑(300行上下),debug的時候會經常用到這個檔案,不更改記錄級別的話提示警告什麼的也在裡面,我也不知道咋回事兒

    LogLevel 表示記錄輸出級別(310行上下),取值文件中有註釋麻煩自己看

    Include 表示要引入的其它配置檔案(原文件中490-530行大量出現),要使用了再詳細瞭解吧

    <Files xx.xx*> 表示檔案訪問許可權,按型別限制

    <IfModule xxx_module> 標籤表示如果載入了 xxx_module 模組就將其內容作為該模組的配置

    <Directory xxxx> 標籤表示資料夾許可權,見第一條 ServerRoot

   3. 安裝/解除安裝系統服務,不安裝沒法用

    安裝:管理員許可權開啟控制檯,cd 到 Apache24/bin/ 目錄下,執行 "httpd -k install" 將Apache服務注入系統,可使用 -n 引數指定服務名(一般不要這麼幹),Ex: "httpd -k install -n "Apache2439" ",如此步安裝過程報錯考慮可能是VC庫版本問題,一般Apache壓縮包中會有一個空檔案,檔名錶示該版本所依賴的VC庫,若無請自行下載

    安裝完成後可到系統服務將該服務 "自動啟動" 改為手動啟動,否則該服務將隨系統開啟而啟動;如果部署到伺服器則不用修改

    解除安裝:管理員許可權開啟控制檯,cd 到 Apache24/bin/ 目錄下,執行 "httpd -k uninstall" 解除安裝服務,若注入服務時使用 -n 引數指定服務名則此處也要用 -n 引數指定

  4. 啟動/停止/重啟服務

    啟動:管理員許可權開啟控制檯,cd 到 Apache24/bin/ 目錄下,執行 "httpd -k start" 開始執行伺服器,若注入服務時使用 -n 引數指定服務名則此處也要用 -n 引數指定

    重啟:"httpd -k restart"

    停止:"httpd -k stop"

    其它:"httpd -h" 可檢視httpd支援的所有命令,當然,是英文版的

  n. 若上述步驟都沒有什麼問題,則訪問 127.0.0.1 就能看到 "It works!" 了(伺服器需允許httpd.exe通過防火牆)

  0x21: Apache+Django部署

  注:Python安裝都不會的就不用繼續看了

  1. 執行模式解釋,Apache伺服器指令碼執行模式有一大堆,具體是咋回事兒我也不是很懂,以下是我對其中一部分的個人理解,若有偏差歡迎指正

    CGI: 伺服器收到請求後由配置資訊找到CGI程式(指令碼)路徑,隨後由該程式指定的執行方式執行(直接執行或解析器),然後將執行結果返回給伺服器呼叫處

    FCGI: GCI的升級版,改進CGI每次伺服器的請求都會呼叫一次CGI程式體浪費空間和效能的缺點;FCGI建立一個程式執行的管理程式,伺服器只與管理程式通訊(通訊機制一般使用socket)。每次請求會被FGCI管理程式分配給工作程式或執行緒,由於管理程式事先會啟動多個工作程式/執行緒,所以省去了事務生成/銷燬的系統開銷

    WSGI: FCGI的改進版,管理程式實現方式改為伺服器外掛而不是使用socket通訊,官方文件中一般使用 Middleware(中介軟體) 這個概念,可避免埠占用,主要效能提升在於降低通訊開銷(記憶體共享快於socket通訊)

  2. 中介軟體 mod_wsgi 是Django在Apache上的一種方案,採用上述WSGI的實現方式

  3. Django安裝,建議直接 "pip install django" 安裝,安裝完成後會有 "Success" 之類的提示,可執行 "pip list" 可檢視安裝包列表內是否有 "Django x.x.x" 以確認安裝

    3.1 pip安裝緩慢原因:下載源在國外,解決:修改下載源,方法:"C:/Users/使用者名稱" 目錄下建立 "pip" 資料夾,資料夾內建立 "pip.ini" 配置檔案,內容為:

      [global]

      index-url = https://pypi.douban.com/simple/

    3.5. Django中一些基礎概念的介紹

      專案:一個Web專案的容器,其中包括該Web專案要用到的所有檔案,例如靜態檔案、Python指令碼、資料庫等

      應用:Web專案中的一個功能的所有實現,程式碼以及資料

      專案和應用是多對多的關係,一個專案可由多個應用構成,一個應用可供多個專案使用

  4. mod_wsgi 安裝,去Python庫裡下載mod_wsgi,模組版本一定要對應Apache和Python的版本,因為這是一箇中介軟體,就是用來適配兩端模組的,再送一張飛機票>> mod_wsgi ,下載到的是 whl 檔案,使用 "pip install mod_wsgi-xxx.whl" 進行安裝

  5. 建立Django專案/應用

    控制檯執行 "django-admin startproject projName" ,生成一個Django專案,同上 django-admin 也在Python 中 Scripts 目錄下,該命令會在指定目錄生成一個Django專案檔案結構,不指定目錄則生成在當前目錄,使用 "django-admin startapp appName" 生成一個應用,貼出自用的一個生成專案和應用的 .bat 指令碼

@echo off
echo.  ** Django **
echo.新建 Django 專案輸入 1
echo.新建 Django 應用輸入 2
set /p cho=輸入後回車: 
goto tag%cho%
:tag1
set /p projName=輸入專案名: 
django-admin startproject %projName%
goto end
:tag2
set /p appName=輸入應用名: 
django-admin startapp %appName%
:end
echo.請自查當前目錄是否生成檔案
pause
newDjango.bat

  

  6. Apache 適配 mod_wsgi 中介軟體,修改配置檔案 httpd.conf

    注:網上一堆找 xxx.so 模組檔案再改上述 httpd.conf 中 LoadModule 是不可行的,因為Python3之後的版本使用的模組為 pyd 格式

    控制檯執行 "mod_wsgi-express module-config" ,該命令中的 mod_wsgi-express 在 Python 目錄中 Scripts 資料夾下,如果環境變數 Path 中沒有該 Scripts 的路徑就 cd 過去再用,將得到的3行結果複製下來,貼上到 Apache 中的 httpd.conf 配置檔案末尾,一般是 LoadFile+LoadModule+WSGIPythonHome,分別表示Python解析器路徑/中介軟體路徑/Python容器路徑(也可執行 "mod_wsgi-express module-config >> ApachePath/conf/httpd.conf",ApachePath代表Apache安裝根目錄,如果你熟悉命令列應該知道這是個啥)

    新增行 " WSGIScriptAlias / "djangoPath/djangoName/wsgi.py" ",該行為Apache找到Django專案提供依據,路徑為Django專案下的 wsgi.py 檔案

    新增行 " WSGIPythonPath "djangoPath" ",該行為Django專案的容器路徑

    配置 wsgi.py 的訪問許可權:

      <Directory "djangoPath/djangoName">

       <Files "wsgi.py">
        Require all granted
       </Files>
      </Directory>

    配置靜態檔案路徑及訪問許可權:

      Alias /static "djangoPath/static"

      <Directory "djangoPath/static">
       AllowOverride None
       Options None
       Require all granted
      </Directory>

    配置多媒體檔案路徑及訪問許可權:(可選)

      Alias /media "djangoPath/media"

      <Directory "djangoPath/media">
       AllowOverride None
       Options None
       Require all granted
      </Directory>

    我的配置程式碼

#配置wsgi.py訪問許可權
WSGIScriptAlias / "D:/Program/Apache/Apache24/htdocs/dj/dj/wsgi.py"
WSGIPythonPath "D:/Program/Apache/Apache24/htdocs/dj"
<Directory "D:/Program/Apache/Apache24/htdocs/dj/dj">
<Files "wsgi.py">
Require all granted
</Files>
</Directory>

#此項為靜態檔案路徑
Alias /static "D:/Program/Apache/Apache24/htdocs/dj/static"
#靜態路徑許可權配置
<Directory "D:/Program/Apache/Apache24/htdocs/dj/static">
AllowOverride None  
Options None  
Require all granted
</Directory>

#此項為多媒體檔案路徑
Alias /media "D:/Program/Apache/Apache24/htdocs/dj/media"
#多媒體許可權配置
<Directory "D:/Program/Apache/Apache24/htdocs/dj/media">
AllowOverride None  
Options None  
Require all granted
</Directory>
httpd.conf

  n. 配置完成以上內容重啟Apache,使用瀏覽器訪問 127.0.0.1 就能看到Django的歡迎介面了(伺服器需要在Django專案中setting.py中設定 "ALLOWED_HOSTS=['*']",詳見Django配置檔案解析)

0x02: 使用Django進行開發(Python3.7+Django2.2.2)

  0x12: Django框架簡介

  1. MVT,應該屬於設計模式什麼的吧,其實思想和MVC差不多

    M(Model): 資料持久層,運算元據庫的

    V(View): 檢視層,其實是控制邏輯的

    T(Template): 模板層,返回給使用者看的內容

  2. 最小檔案結構,執行 "django-admin startproject projName" 生成

  projName

   |-- projName<DIR>

   |--  |--  __pycahce__<DIR> #首次執行後自動生成的Python二進位制檔案

   |--   |--  ....pyc

   |--  |--  __init__.py #空檔案,Python模組標識

   |--  |--  setting.py #該專案的配置資訊

   |--  |--  urls.py #該專案的所有URL路由

   |--  |--  wsgi.py #WSGI的介面??

   |-- db.selite3 #專案首次執行後自動生成的資料庫檔案(若未修改Django預設使用的資料庫SQLite3)

   |-- manage.py #管理該專案的檔案

  3. 擴充套件檔案結構,自行建立(可選)的檔案結構

    projName/templates<DIR>: 放置html檔案的路徑,Django中成為模板檔案

    projName/static<DIR>: 放置靜態檔案,包括css/js/image

    projName/media<DIR>: 放置多媒體檔案,大概除了上面兩個其它的檔案都可以放這兒吧,也不是很懂這是幹嘛的

    projName/projName/views.py: 檢視檔案,其實名字隨便取,但最好這樣(江湖規矩)

    projName/projName/models.py: 模型檔案,用來編寫模型的,只能是這個名字好像

  0x22: 專案配置,setting.py

    BASE_DIR: 專案所在路徑,不常改

    SECRET_KEY: 啥金鑰來著??不常改

    DEBUG: 除錯模式預設為True,用於輸出除錯資訊,專案上線後應改為False

    ALLOWED_HOSTS: 允許通過的地址,上線後一般設定為['*']

    INSTALLED_APPS: 安裝的應用,建立應用後需要在此新增

    MIDDLEWARE: Django提供的工具集,如CSRF

    ROOT_URLCONF: url配置檔案,指向專案下的urls.py路由檔案,一般不改

    TEMPLATES: 模板配置檔案

    WSGI_APPLICATION: CGI應用例項,一般不改

    DATABASES: 資料庫配置

    AUTH_PASSWORD_VALIDATORS: 密碼認證配置,一般不改

    # 以下為國際化配置

    LANGUAGE_CODE: 語言('zh-hans'),設定為中文後Django主頁顯示為中文

    TIME_ZONE: 時區('Asia/Shanghai')

    USE_I18N: 國際化

    USE_I10N: 國際化

    USE_TZ: 時間儲存帶時區(False)

    STATIC_URL: 靜態檔案(CSS/JS/Image/Fonts)位置('/static/')

    # 以下為非預設配置

    APPEND_SLASH: 自動在url後加 '/', 預設為True

    STATICFILES_DIRS: 靜態檔案路徑,設定為 (os.path.join(BASE_DIR, 'static'),) 否則使用Django自帶伺服器啟動時不能訪問靜態檔案

  0x32: 其它常用操作

  1. 資料遷移,資料庫生成與更改後都應執行資料遷移指令,控制檯執行以下命令

    python manage.py makemigrations #建立資料庫資料夾migrations(存在則跳過)

    python manage.py migrate #生成資料表及填充許可權

    建立管理員使用者,用於登入Django的控制檯 127.0.0.1/admin

      python manage.py createsuperuser #建立管理員,然後輸入一堆資訊就成了

  2. 新應用目錄結構,略

  3. 啟動Django自帶的Web除錯伺服器,只能用作除錯,併發性為0

    控制檯cd到Django專案根目錄下,執行 "python manage.py runserver",Django會在127.0.0.1:8000開啟伺服器,runserver 可選引數為[ip:port]

  4. 新增應用後,應在 setting.py 檔案中的 INSTALLED_APPS 中新增該應用的名稱

  5. 使用MySQL資料庫,大概記錄一下(我使用的預設的sqlite,沒有用MySQL)

    MySQL資料庫安裝,請自行百度

    Python MySQL連線驅動安裝,老規矩 "pip install pymysql"

    專案中使用MySQL資料庫需要在 __init__.py 中初始化資料庫,程式碼為:

      import pymysql

      pymysql.install_as_MySQLdb()

    修改專案 setting.py 檔案資料庫部分:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', #Django中Model的實現
        'NAME': 'dbName', #資料庫名稱
        'USER': 'loginUserName', #登入使用者
        'PASSWORD': 'loginPwd', #登入密碼
        'HOST': '127.0.0.1', #資料庫位置
        'PORT': '3306', #資料庫監聽埠
    }
}
DATABASES

  6. setting.py 模板路徑設定,TEMPLATES 中 'DIRS':[BASE_DIR+'/templates',]

  7. Django後臺管理工具,以下只做簡要介紹,其它請自行查詢

    訪問 127.0.0.1/admin進入管理頁面(未登入顯示登入)

    伺服器部署 頁面沒有css樣式原因:未作 admin 靜態檔案遷移(Apache配置檔案中將許可權交給Django後沒有決定路徑解析的許可權),解決:將 "PythonPath/Lib/site-packages/django/contrib/admin/static" 目錄下的 "admin" 目錄拷至 "ApachePath/htdocs/djangoName/static" 資料夾下

  8. Ajax禁止問題,報錯為 "CSRF token missing or incorrect.",原因:CSRF阻止,解決:註釋掉配置檔案 setting.py 中 "MIDDLEWARE" 中的 csrf 外掛

  0x42: 開發部分

  1. 核心部分概述

    urls.py: Django中的路由系統,說明網址與檢視層(函式呼叫)的對映關係

    views.py: Django中的檢視層,其中放置的函式供路由系統呼叫

    models.py: Django中的模型層,供檢視層呼叫,用於處理資料持久化,遮蔽相對底層的操作(直接操作SQL語句),當然Django也提供直接執行SQL語句的介面,但不建議你這麼幹

  2. urls.py, views.py, models.py

###########urls.py###########
# 當 "urlpatterns" 條目為空或只存在 admin 對映時訪問 127.0.0.1 會對映到Django預設主頁

from django.contrib import admin
from django.urls import path
from . import views #存在 views.py 檔案時可匯入檢視檔案以使用其中的函式

urlpatterns = [
    path('admin/', admin.site.urls), #將.../admin對映到Django管理介面
    path('sayHello/', views.sayHello), #呼叫 sayHello 檢視
]

###########views.py###########
# 使用 "django-admin startapp appName" 建立的應用自動生成該檔案

from django.shortcuts import render,HttpResponse,redirect #通常使用這3種方式返回
from . import models #如需使用則手動建立該檔案

def sayHello(request):
    return HttpResponse('Hello Django.')

###########models.py###########
#使用 "django-admin startapp appName" 建立的應用自動生成該檔案
#修改本檔案中內容後執行資料遷移指令,自動生成資料庫結構對映

from django.db import models

# 模型建立示例
class User(models.Model):
    name=models.CharField(primary_key=True,max_length=16)
    age=models.IntegerField(default=0)
View Code

    編寫完成後重啟伺服器,訪問 127.0.0.1:8000/sayHello 就能看到結果了

  3. 一個使用模板+靜態資源的示例setting.py 中需配置 STATICFILES_DIRS 的值

    檔案結構

   projName

    |--  projName<DIR>

     |--  __init__.py

     |--  settings.py

     |--  urls.py

     |--  views.py

     |--  wsgi.py

    |--  static<DIR>

     |--  templateTest.css

     |--  templateTest.jpg

     |--  templateTest.js

    |--  templates<DIR>

     |--  templateTest

    |--  manage.py

##################urls.py##################
from django.urls import path
from . import views

urlpatterns = [
    path('<int:pageNum>/',views.template),
]

##################views.py##################
from django.shortcuts import render

def template(request,pageNum):
    content={
        'pageNum':pageNum,
    }
    return render(request,'templateTest.html',content)

##################templateTest.html##################
<!DOCTYPE html>
<html>
<head>
    <title>testPage</title>
    <link rel="stylesheet" type="text/css" href="../static/templateTest.css">
</head>
<body>
    <p>圖片顯示為圓形則css/圖片載入成功</p>
    <p>彈出對話方塊則javascript指令碼載入成功</p>
    <p>括號內為位址列輸入的數字({{pageNum}})</p>
    <img src="../static/templateTest.jpg">
    <script type="text/javascript" src="../static/templateTest.js"></script>
</body>
</html>

##################templateTest.css##################
img{
    width: 200px;
    height: 200px;
    border-radius: 50%;
}

##################templateTest.js##################
document.onload=alert('呼叫javascript');
View Code

0x03: 後記

  寫得有點久了,95%是在做東西的時候寫的,到釋出的時候已經快一個月時間了,其中有些東西現在也記不大清了;當時沒有釋出我覺得可能有些重要的地方沒寫完,釋出之前我又重新把上面的東西都跑了一次,發現果然是有些東西沒寫到 0.0

  這篇文章可能不是描述的最詳細的,但應該是這一套技術比較全面的了,如果有什麼問題或建議請回複評論(雖然最後確實頭都寫暈了 555~)

  原創文章,轉發請註明

 

相關文章