Django 站点部署和管理常用命令

晨曦之光 发布于 2012/05/23 11:02
阅读 7K+
收藏 14

原文:Django 站点部署和管理常用命令
作者:Breaker <breaker.zy_AT_gmail>


通过 The Django Book 学习建立、部署和管理 Django 站点的笔记,内容重点 章节 12:部署 Django

Django 与 The Django Book 版本对应关系

Django 0.96 参考 Django Book 1.0
Django 1.0 或以上 参考 Django Book 2.0

本文使用 Django 1.1,以下简称 Django 为 dj

建立 Django 工程和应用

1. 建立 Django 站点工程

django-admin.py startproject projectname

将创建目录 projectname,projectname 是一个工程 (Project),一个 Project 下可以有多个 dj 应用 (App)
一个 App 包括模型 (Model) 和视图 (View),按 Python 的包结构组织
最简单的情况是,不创建 App,Python 代码都放到 Project 根目录下的 views.py 中
如果要使用 dj 的 Model(数据库层),则必需建立一个 App

2. 建立 App

python manage.py startapp appname

建立 App 后,在 settings.py 中将 appname 加入到 Project 的 INSTALLED_APPS 中:

INSTALLED_APPS = (
'django.contrib.auth',      # INSTALLED_APPS 中已有一些默认的 app
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'projectname.appname',      # 使用 Python 的目录层级格式:包名.子包名.模块名
)
3. 验证 Model
python manage.py validate

验证 (validate) Model 不需要创建数据库

4. 打印 Model 建立数据库表的 SQL 语句

python manage.py sqlall appname

如果 validate 失败,这里也会失败
dj 分析 Model 和 settings.py 中 DBMS 的设置 推导出 SQL 语句

5. 建立 Model 数据库表

python manage.py syncdb

dj 自动连接 DBMS,根据 Model 建立数据库表,即执行上面打印的 SQL 语句
但是修改了 Model 之后,不能直接用 syncdb 同步修改表,必需先把表删了,再用 syncdb

6. 创建站点管理员用户

python manage.py createsuperuser

如果 settings.py 的 INSTALLED_APPS 中有 django.contrib.auth,当第一次运行 syncdb 时会询问是否创建站点管理员用户
如果当时不创建管理员的话,后来可以运行 createsuperuser 来创建
使用 django-admin.py 管理站点时,需要 django.contrib.auth

7. 启动 DBMS 客户端管理程序

python manage.py dbshell

启动设置的 DBMS 的客户端管理程序,如 MySQL 的 mysql.exe

8. 启动 Django 站点的 Python 交互解释器

python manage.py shell

启动一个 Python shell,在其中可以执行 Model 类的方法,向数据库中插入/更新数据

django-admin.py 和 manage.py 的关系

django-admin.py

属于 dj 的全局管理工具,dj 安装后,放在 <Python 安装目录>/lib/site-packages/django/bin
用 django-admin.py help 查看用法

manage.py

每个 dj Project 的管理工具,manage.py 的功能 django-admin.py 都能完成

manage.py 默认导入同目录下的 settings.py 最为该 Project 的设置文件
如果用 django-admin.py 管理 Project,需要指定 dj 工程设置模块(一般为 settings.py),否则 django-admin.py 不知道管理哪个 Project

django-admin.py 指定 工程设置模块 的方法:

1. 使用 --settings

django-admin.py [command] --settings="myproject.settings.main"

# 以当前路径下的 settings.py 为 工程设置模块
django-admin.py runserver 0.0.0.0:8080 --pythonpath="." --settings="settings"

--setting: 指定 工程设置模块,使用 Python 的目录层级格式
--pythonpath: 可能在 PYTHONPATH (sys.path) 中找不到 --settings 指定的路径,这时需要指定 --pythonpath

2. 使用 DJANGO_SETTINGS_MODULE 环境变量

如果没指定 --settings,就从 DJANGO_SETTINGS_MODULE 环境变量中获得:

# 类 Unix 环境变量
export DJANGO_SETTINGS_MODULE=projectname.settings.main

# Windows 环境变量
set DJANGO_SETTINGS_MODULE=myproject.settings.main

Django 内建 Web 服务器

python manage.py runserver 0.0.0.0:8080

使用 dj 内建的 Web 服务器启动 dj 站点
从 HTTP 返回头域中可知 dj 内建的 Web 服务器名为 WSGIServer
dj 内建服务器是 调试/测试服务器,Apache mod_python、FastCGI 等是 部署服务器,dj 内建服务器暴露的 request.META 信息较多

Apache mod_python 部署 Django

使用 Apache mod_python 部署时的问题:

mod_python 缓存 Python 代码

dj 内建服务器 runserver 会自动扫描 Project 设置文件 (settings.py) 的改动,当保存新的设置文件后,runserver 的控制台中会打印信息,但 mod_python 不会自动扫描 Project 设置文件的改动,更改设置文件后,必需重启 Apache

mod_python 和 mod_php 方式不同:对于 PHP,更改代码后会立即作用,而对于 Python,更改代码后,因为 mod_python 会预载入 Python 代码(缓存),所以需要重启 Apache

可在 Apache 配置文件中设置 MaxRequestsPerChild 1,强制在每个请求时都重新载入所有代码(影响性能)

经测试 (Apache 2.2.6, mod_python 3.3.2),发现即使设置 MaxRequestsPerChild 1,更改后的 Python 代码仍会缓存两三次不定,即浏览器需要刷新两三次地址可以得到最新的页面内容

mod_python 中的 Python 源代码暴露

Python 源代码暴露:浏览器直接访问作为服务器脚本程序 .py、.pyc 文件的 URL 时,应该不显示、返回下载这些文件的内容,否则会造成源码暴露安全问题

Apache mod_python 的 Django 配置示例:

################################################################################
# mod_python 方式使用 Django
# BEGIN
#
# Location 指定 URI,而 Directory 指定本地路径
<Location "/dj/">
SetHandler python-program
PythonHandler django.core.handlers.modpython

# 设置 PYTHONPATH,同 django-admin.py --pythonpath
PythonPath "['C:\\web\\pub\\dj'] + sys.path"

# 设置 dj 工程设置模块,同 django-admin.py --setting
SetEnv DJANGO_SETTINGS_MODULE djproject.settings_release

# 可设置多个 dj Project 的 <Location> 目录,此时需要有 PythonInterpreter
# PythonInterpreter 的值并不重要,只起标识作用,在多个 <Location> 中各不同
# PythonInterpreter djproject

PythonDebug Off
</Location>
#
# END
################################################################################

1. dj Project 目录 <Location> 下的 .py、.pyc 文件不会暴露,请求这里的 URL 会按照 urls.py 的 URL 映射规则处理

2. 如果设置了通用 CGI Python 脚本处理 AddHandler cgi-script .py .pyc,在 dj Project 目录 <Location> 之外也不会暴露代码

3. 以上两种情况之外,.py、.pyc 分别会按 MIME 类型 text/plain、application/octet-stream 处理,会暴露代码

mod_python 中的资源文件

资源文件:Django 动态网页中引用的 css、js、文本、图片、视频、音频 等资源文件

资源文件不应该放到 dj Project 目录下,因为请求这里的 URL 会按照 urls.py 的 URL 映射规则处理,如果不加入资源文件的 URL 映射规则,将无法找到资源文件(404 错误)

几种解决方法:

1. 使用另一个 Web 服务,或虚拟服务 <VirtualHost> 来伺服这些资源文件,在 dj 的页面中引用这里的 URL

2. 在特定的目录下伺服资源文件

如果这个目录是 dj Project 的 <Location> 之外的目录则不需要设置

如果这个目录是 dj Project 的子目录,则需要用 SetHandler None 覆盖 dj Project 目录的 SetHandler python-program 设置,如:

<Location "/dj/media/">
SetHandler None
</Location>

3. 利用 <LocationMatch> 正则表达式匹配资源文件,再用 SetHandler None 覆盖 dj Project 目录的 SetHandler python-program 设置,如:

<LocationMatch "\.(jpg|gif|png)$">
SetHandler None
</LocationMatch>

采用 FastCGI 方式部署与 mod_python 的情况不同,FastCGI 方式可用 mod_rewrite 规则让 Apache 伺服 dj Project 目录下的资源文件,见下面 FastCGI 方式部署

错误与调试

print 打印调试

在 dj 内建服务器 runserver 中,print 语句会打印到 runserver 启动的控制台

在 mod_python 中,print 语句无法输出到控制台或文件,也不会出现在 Apache 的日志文件中

如果需要日志功能,可利用 Python 标准日志包 Pythons standard logging package

Django 中的 Python 错误

Python 语法、逻辑错误被 dj 捕捉,但不会传播到 Apache,不会出现在 Apache 的错误日志中

但是,如果是设置错误(settings.py、urls.py 等),会记录在 Apache 的错误日志中,以 Python 的 traceback 形式,并且返回一个 500 服务器内部错误页面

mod_python 常见错误

下面错误导致 dj 崩溃:

1. 使用 pyexpat 模块(XML 解析),与 Apache 内置的版本冲突,参考 Expat Causing Apache Crash

2. 同时使用 mod_python 和 mod_php,且都使用 MySQL 作为数据库,php 和 python 的 MySQL 模块版本冲突,见 mod_python 的 FAQ

Apache FastCGI 部署 Django

FastCGI 可分为两种方式:

1. 独立运行的 FastCGI 服务,如:

a. 用 dj 内建的 runfcgi 启动 FastCGI 服务,runfcgi 需要 flup 库的支持

b. 使用 lighttpd,它内建 FastCGI 服务

2. 让 Apache 启动子进程 FastCGI 服务 (Web Server-spawned Processes),一般用在共享主机托管服务中,因为共享主机服务商一般不提供更改 Apache 主配置文件的权限,并且不能创建 socket 监听服务 runfcgi

使用 Django 内建的 runfcgi

manage.py runfcgi 命令选项

查看 runfcgi 的所有选项:

manage.py runfcgi help

如果使用 Model,即使只是查看 help 帮助,也需启动数据库服务

protocol: runfcgi 支持多种网关协议,如 fcgi、scgi、ajp,默认 protocol=fcgi
method: runfcgi 工作方式 prefork、threaded,默认 method=prefork,不过 Windows 下没有实现 flup.server.fcgi_fork
socket: socket=/tmp/fcgi.sock 以 UNIX domain socket 方式监听 fcgi,在 Windows 下是命名管道,实测时 Windows 下不能成功
daemonize: daemonize=true 或 false,表示是否在后台运行 fcgi,在 Windows 下看不出效果

例如,在 localhost:3033 上以 threaded 方式运行 runfcgi:

manage.py runfcgi method=threaded host=localhost port=3033

用 django-admin.py 启动 runfcgi 时的模板搜索路径

用 Python 语句 print('**** TEMPLATE_DIRS=%s' % TEMPLATE_DIRS) 查看模板搜索路径

1. 如果在 settings.py 中指定 TEMPLATE_DIRS 为:

TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\', '/'),    # 这是元组,注意后面的逗号 ,
)
则 django-admin.py runfcgi 需要一个绝对路径指定 dj Project 的位置:
django-admin.py runfcgi --settings="settings" --pythonpath="/full/path/to/dj-project" method=threaded host=localhost port=3033

2. 如果在 settings.py 中将 TEMPLATE_DIRS 展开为全路径:

TEMPLATE_DIRS = (
os.path.join(os.path.abspath(os.path.dirname(__file__)), 'templates').replace('\\', '/'),
)
则 django-admin.py runfcgi 可以使用相对路径 --pythonpath=".":
django-admin.py runfcgi --settings="settings" --pythonpath="." method=threaded host=localhost port=3033

Apache mod_fastcgi 和 mod_rewrite 配置

################################################################################
# mod_fastcgi + 独立 FastCGI 服务 方式使用 Django
# BEGIN
#
FastCGIExternalServer C:/web/pub/dj/dj.fcgi -host localhost:3033
<Directory "C:/web/pub/dj">
Options Indexes FollowSymLinks
AllowOverride FileInfo
Order allow,deny
Allow from all
</Directory>

RewriteEngine On
# 不存在文件时,才进行重定向
RewriteCond %{REQUEST_FILENAME} !-f
# 重定向以 /dj/ 打头的 URI
RewriteRule ^/dj/(.*)$ /dj/dj.fcgi/dj/$1 [QSA,L]
#
# END
################################################################################

1. 注意 FastCGIExternalServer 指定的文件 C:/web/pub/dj/dj.fcgi 不一定要存在,但其目录 C:/web/pub/dj 必需存在

2. RewriteRule 的 /dj/dj.fcgi/dj/$1 分为两部分:

a. 前部分 /dj/dj.fcgi,和 FastCGIExternalServer 设置的 .fcgi 匹配
b. 后部分 /dj/$1,是 Apache 请求 fcgi 服务的 URI

3. urls.py 中的 URI 模式应该是 '^dj/xxx/$' 形式(dj 会去掉前缀 /),和 2.b 的 /dj/$1 对应

FastCGI 中的 Python 源代码暴露和资源文件

mod_rewrite 配置 RewriteCond %{REQUEST_FILENAME} !-f 指定当请求的 URI 找不到文件时,才开始重定向,所以可在 dj Project 下存放资源文件

这引发一些问题:

1. 当请求 dj Project 下的 .py、.pyc 文件时,会返回其文件内容,造成源码暴露

2. 如果同时使用通用 CGI Python 脚本处理 AddHandler cgi-script .py .pyc,当请求 dj Project 目录下的 .py、.pyc 时,Apache 会以 CGI 方式运行 Python 程序,但它们是 dj 程序而非通用 CGI 程序,将导致 Apache 内部 500 错误

解决方法:

1. 解决问题 2:修改 Apache 配置,在 dj Project 的目录下,用 RemoveHandler .py .pyc 或 SetHandler cgi-script 的方法,覆盖继承的 handler

2. 解决问题 1:使用 mod_rewrite 重定向,隐藏 .py、.pyc 文件,如 RewriteRule .*\.pyc?$ /ERR404/ [L,NC]

FastCGI 页面请求过程

HTTP 请求过程如下:

1. 浏览器 URL=http://localhost/dj/xxx/, URI=/dj/xxx/

2. 经 Apache 的 mod_rewrite 重定向规则 /dj/xxx/ => /dj/dj.fcgi/dj/xxx/,Apache 请求 FastCGI 服务的 URI=/dj/xxx/

3. 经 dj 的 urls.py URL 匹配规则 URI=/dj/xxx/(dj 会去掉前缀 /),调用匹配的 View 函数 app.views.xxx_handler

让 Apache 启动子进程 FastCGI 服务

一般在 Linux 共享主机托管服务中使用这种方法

FastCGI 启动脚本

FastCGI 启动脚本 dj.fcgi:

#!/usr/bin/python2.6
#coding=utf-8

import sys, os

# 加入 PYTHONPATH
sys.path.insert(0, "/home/somebody/public_html/dj")

# dj Project 的工作目录
# os.chdir(r"/home/somebody/public_html/dj/mydj")

# dj Project 的设置模块,环境变量 DJANGO_SETTINGS_MODULE
os.environ['DJANGO_SETTINGS_MODULE'] = "mydj.settings_release"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(method = "threaded", daemonize = "false")
该脚本以 CGI 方式运行,Apache 配置中需要启动该脚本目录的 CGI 执行权限 Options ExecCGI

runfastcgi() 函数是 Django 内建 FastCGI 服务 manage.py runfcgi 的内部运行函数,runfastcgi() 可接受的参数就是 manage.py runfcgi 的选项

runfastcgi(method = "threaded", daemonize = "false") 默认以 UNIX domain socket 方式启动子进程 FastCGI 服务,子进程为 Python 解释器

Windows 下使用 UNIX domain socket 方式报错(可能没实现),Apache 日志:

File "D:\tool\develop\Python26\lib\site-packages\flup\server\fcgi_base.py", line 978, in _setupSocket
sock = socket.fromfd(FCGI_LISTENSOCK_FILENO, socket.AF_INET,
AttributeError: 'module' object has no attribute 'fromfd'

Windows 下使用监听 socket 方式运行 runfastcgi(settings = "settings", pythonpath=".", method = "threaded", host = "localhost", port = "3033", daemonize = "false"),可看到 Apache 产生 10 个 Python 解释器子进程,都监听 TCP 3033 端口(没有发生监听端口重复错误)

mod_rewrite 重定向

Apache 目录级配置 .htaccess 中

RemoveHandler .py .pyc
AddHandler fcgid-script .fcgi
# 有的版本 mod_fastcgi 使用 fastcgi-script,而不是 fcgid-script
# AddHandler fastcgi-script .fcgi

RewriteEngine On

# 防止代码暴露
RewriteRule .*\.pyc?$ /ERR404/ [L,NC]

# 不存在文件时,才进行重定向
RewriteCond %{REQUEST_FILENAME} !-f
# .htaccess 目录下的所有请求都交给 FastCGI 启动脚本 dj.fcgi 处理
RewriteRule ^(.*)$ dj.fcgi/$1 [QSA,L]

加载更改的 Python 代码

更改 dj Project 代码后,只需重新加载 FastCGI 启动脚本 dj.fcgi,便可重新加载更改后的 Python 代码。不用重启 Apache,只需更新 dj.fcgi 的文件时间戳,Apache 便会重新加载 dj.fcgi,如使用 touch mysite.fcgi

部署 Django 工程的不同版本

以示例说明,一个 dj Project 有以下不同版本,它们有各自特定的 设置 或 工程设置模块:

1. 开发平台是 Windows,实际部署平台是 Linux,两者是不同的主机,根据主机名使用不同的设置

2. 调试版 (Debug) 和 发布版 (Release),使用不同的工程设置模块 settings.py

Debug 版 工程设置模块 settings_debug.py 如下(演示如何区分各版本,无关代码从略):

#coding=utf-8
import os.path
import socket

# 假设本地 Windows 主机名为 my-host
# IS_LOCALHOST 表示当前 dj Project 是否运行在本地主机,即开发平台上
MY_HOSTNAME = socket.gethostname().lower()
IS_LOCALHOST = (MY_HOSTNAME.find('my-host') != -1 or MY_HOSTNAME.find('localhost') != -1)

# 开启调试开关
DEBUG = True
TEMPLATE_DEBUG = DEBUG

# 根据 IS_LOCALHOST 设置不同的数据库连接参数
DATABASE_ENGINE = 'mysql'
DATABASE_NAME = 'local_db' if IS_LOCALHOST else 'deploy_db'
DATABASE_USER = 'local_user' if IS_LOCALHOST else 'deploy_user'
DATABASE_PASSWORD = 'local_pwd' if IS_LOCALHOST else 'deploy_pwd'
DATABASE_HOST = ''
DATABASE_PORT = ''

# 根据 IS_LOCALHOST 设置不同的资源文件的存储位置
MEDIA_ROOT = 'C:/web/pub/res/' if IS_LOCALHOST else '/home/somebody/public_html/res/'

Release 版 工程设置模块 settings_release.py 如下:

#coding=utf-8

# 导入 Debug 版 工程设置模块
from settings_debug import *

# 关闭调试开关
DEBUG = False
TEMPLATE_DEBUG = False

# 设置邮箱地址,dj Project 出错时,发邮件通知
EMAIL_SUBJECT_PREFIX = '[django][mydj]'
EMAIL_HOST = 'localhost'

ADMINS = (
    ('somebody', 'somebody@somedomain'),
)

SEND_BROKEN_LINK_EMAILS = True
MANAGERS = ADMINS

用 manage.py runfcgi --settings 选项、runfastcgi() 的 settings 参数 或 DJANGO_SETTINGS_MODULE 环境变量指定不同的 工程设置模块 settings_debug.py、settings_release.py


原文链接:http://blog.csdn.net/breakerzy/article/details/6899400
加载中
返回顶部
顶部