Django中调试和生产环境配置静态文件的常见方式是什么
在开发Django应用时,如果我处于调试模式,我会用以下代码来提供静态文件:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^m/(?P<path>.*)$', serve, {
'document_root' : os.path.join(os.path.dirname(__file__), "media")
})
)
在生产模式下,我使用nginx作为前端来提供我的静态文件,配置如下:
location m/
{
root /path/to/folder/media/;
}
这样做似乎不太理想,因为我需要在媒体目录下创建一个“m”文件夹。我想知道大家的Django/nginx配置文件是怎样的。具体来说,能不能请你们分享一下nginx.conf和urls.py的部分内容(当settings.DEBUG == True时)
谢谢。
2 个回答
我把这些内容放在这里,以便有需要的人能看到如何在Apache和WSGI中实现这个功能。问题的标题表述得很清楚,不仅仅是针对nginx。
Apache/WSGI守护进程
在我的部署中,我决定把数据库连接信息放在settings.py
文件之外。相反,我有一个路径/etc/django
,里面包含数据库配置的文件。这在另一个问题的回答中有详细说明。不过,作为一个附带效果,我可以检查这些文件是否存在,以及项目是否在某个路径下,以此来判断它是否在运行部署。在settings.py
中,我定义了IS_DEV
、IS_BETA
和IS_PROD
这几个设置,值为True
或False
。从settings.py
中找到项目的目录很简单:
# Find where we live.
import os
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
任何需要项目路径的地方都使用BASE_DIR
。所以在urls.py
的最后,我有:
# Only serve static media if in development (runserver) mode.
if settings.IS_DEV:
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT,
'show_indexes': True}),
)
(我在这里还有另一个URL,用于UI测试,不想在beta或生产环境中出现。)
这部分讲的是开发服务器的情况。对于生产环境,我只需要设置Apache的配置来提供静态文件。(这是一个内部网络应用,负载较低到中等,所以我没有像lighttpd这样的轻量级web服务器来提供静态文件,这与Django文档的建议相反。)因为我使用的是Fedora Core,我在/etc/httpd/conf.d
中添加了一个django.conf
文件,内容类似于:
WSGIDaemonProcess djangoproject threads=15
WSGISocketPrefix /var/run/wsgi/wsgi
Alias /django/static/ /var/www/djangoproject/static/
Alias /django/admin/media/ /usr/lib/python2.6/site-packages/django/contrib/admin/media/
WSGIScriptAlias /django /var/www/djangoproject/django.wsgi
WSGIProcessGroup djangoproject
<Directory /var/www/djangoproject>
Order deny,allow
Allow from all
</Directory>
<Directory /usr/lib/python2.6/site-packages/django/contrib/admin/media>
Order deny,allow
Allow from all
</Directory>
如果我没记错,关键是要把Alias
行放在WSGIScriptAlias
行之前。同时确保用户无法下载你的代码;我通过把静态文件放在一个不在我的Django项目中的static
目录来实现。这就是为什么BASE_DIR
给出的目录是包含Django项目目录的。
你可以省略WSGISocketPrefix
这一行。我之所以有它,是因为管理员希望把套接字放在一个非默认的位置。
我的WSGI文件在/var/www/djangoproject/django.wsgi
(也就是在Mercurial仓库中的/django.wsgi
),内容大概是:
import os
import sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'djangoproject.settings'
os.environ['DB_CONFIG'] = '/etc/django/db_regular.py'
thisDir = os.path.dirname(__file__)
sys.path.append(thisDir)
sys.path.append(os.path.join(thisDir, 'djangoproject'))
sys.path.append(os.path.join(thisDir, 'lib'))
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
WSGI守护进程的好处是,你只需要touch django.wsgi
就能重启你的Django WSGI守护进程;你不需要重新加载或重启Apache服务器。这让管理员很满意。
最后,由于我的/var/www/djangoproject
只是一个Mercurial仓库,我在/var/www/djangoproject/.hg/hgrc
中有以下内容:
[hooks]
changegroup.1=find . -name \*.py[co] -exec rm -f {} \;
changegroup.2=hg update
changegroup.3=chgrp -Rf djangoproject . || true
changegroup.4=chmod -Rf g+w,o-rwx . || true
changegroup.5=find . -type d -exec chmod -f g+xs {} \;
changegroup.6=touch django.wsgi # Reloads the app
这会清除Python字节码,更新工作副本,修复所有权限,并在开发者推送到部署时重启守护进程,这样djangoproject
组中的任何人都可以推送,而不仅仅是最后一个添加文件的人。不用说,添加到djangoproject
组的人要小心。
zeekay设置了STATIC_URL
、STATIC_ROOT
、STATICFILES_DIRS
、STATICFILES_FINDERS
,并在他的设置中使用了"django.contrib.staticfiles"
和"django.core.context_processors.static"
。我没有这些,因为我的代码是Django 1.1时代的,不使用{{ STATIC_ROOT }}
。
希望这些内容对你有帮助。
在使用 Django 1.3 的时候,django.contrib.staticfiles
会帮你处理开发过程中所有的静态文件,你不需要在 urls.py 里做什么特别的设置。我在 Django 1.3 更新后写了一个小指南,记录了需要使用的设置:
# idiom to get path of project
import os
PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
# url prefix for user uploaded files, stuff that django has to serve directly
MEDIA_URL = '/media/'
# url prefix for static files like css, js, images
STATIC_URL = '/static/'
# url prefix for *static* /admin media
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
# path to django-served media
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')
# path used for collectstatic, *where the webserver not django will expect to find files*
STATIC_ROOT = '/home/user/public_html/static'
# path to directories containing static files for django project, apps, etc, css/js
STATICFILES_DIRS = (
os.path.join(PROJECT_PATH, 'static'),
)
# List of finder classes that know how to find static files in various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
# Required for all the magic
INSTALLED_APPS = (
'django.contrib.staticfiles',
)
详细信息可以参考文档:http://docs.djangoproject.com/en/1.3/howto/static-files/。
在生产环境中,我使用 nginx 和 uwsgi 来运行 Django 应用(开发时我用 runserver)。我把我的 /static
和 /media
文件夹(来自我的 Django 项目)做成符号链接,放到 /var/www/vhosts/domain.com/html
里,这样 nginx 就能找到它们。如果找不到静态文件,它会回退到 uwsgi(也就是运行 Django 应用的地方)。
你也可以用 fast-cgi,或者 proxy_pass,或者其他你想用的方式来替代 uwsgi。我更喜欢 uwsgi,因为它有很多功能,性能也很好。我把 uwsgi 作为守护进程运行,命令是:uwsgi --emperor '/srv/*/*.ini'
。这个选项比较新,它告诉 uwsgi 去扫描指定路径下的配置文件。当 uwsgi 守护进程找到一个配置文件时,它会根据这个配置启动一个新的 uwsgi 实例。如果你更改了配置,uwsgi 守护进程会注意到并为你重启应用。你也可以像 mod_wsgi 一样触碰配置文件来重新加载,一旦你初始配置好后,设置新应用非常简单。
我遵循的路径约定是:
/srv/venv/ - virtualenv for project
/srv/venv/app.ini - configuration for uwsgi
/srv/venv/app.sock - uwsgi sock for django
/srv/venv/app.wsgi - wsgi file for uwsgi
/srv/venv/proj - django project
/srv/venv/proj/settings.py - project settings file
/srv/venv/proj/static - static files dir, linked into var/www/vhosts/domain.com/html
/srv/venv/proj/static/admin - admin static files, linked as well
/srv/venv/proj/media - media files dir
/var/www/vhosts/domain.com/html - base directory for nginx to serve static resources from
这是我的 nginx.conf 文件:
location / {
root /var/www/vhosts/domain.com/html;
index index.html index.html;
error_page 404 403 = @uwsgi;
log_not_found off;
}
location @uwsgi {
internal;
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:/srv/venv/app.sock;
}
我的 uwsgi ini 文件(你也可以使用 xml/yaml 等格式):
[uwsgi]
home = /srv/%n
pp = /srv/%n
wsgi-file = /srv/%n/%n.wsgi
socket = /srv/%n/%n.sock
single-intepreter = true
master = true
processes = 2
logto = /srv/%n/%n.log
你还应该看看 gunicorn,它与 Django 的集成非常好,性能也不错。