看似很單純的事, 結果做起來有夠麻煩, 不知大家是怎麼做的? 網路上的範例幾乎都是將 project 放到根路徑, 即 http://.../。但若想在一台機器上放多個 project 的話, 就得額外處理。可能的做法有:
- 註冊多個 domain name, 配合 apache 的 virtualhost 將不同 domain name 對到不同的 project。如此一來全部 project 都能用根路徑。
- 將 project 放到子路徑: http://.../foo/, http://.../bar/。
我不想申請 domain name, 所以就選第二個方案。需要更改的東西有:
- settings.py
- urls.py
- myapp/views.py
- template/*.html
- apache conf
做法如下。
settings.py
# 不同 project 設不同的 site_root, 像是 '/foo/' 或 '/bar/'
SITE_ROOT = '/'
MEDIA_URL = SITE_ROOT + 'media/'
ADMIN_MEDIA_PREFIX = SITE_ROOT + 'admin_media/'
# auth 要用到的 URL 設定
LOGIN_URL = SITE_ROOT + 'login/'
LOGIN_REDIRECT_URL = SITE_ROOT
在 views 裡記得用 RequestContext, 這樣 template 裡才能直接取用 {{ MEDIA_URL }}。
urls.py
# 路徑都改用 url 設名字, 之後才能在 template 中用 url tag 指回 view。
url(r'^$', views.index, name='index'),
url(r'^login/$', 'django.contrib.auth.views.login', name='login'),
url(r'^logout/$', 'django.contrib.auth.views.logout_then_login', name='logout'),
...
# 順便提一下, 跑在 production server 上時會直接用 apache 傳靜態檔案,
# 但開發時是用 Django 的 web server, 所以要要自己處理靜態檔案
if settings.DEBUG:
# Define url routes for static files in development mode.
urlpatterns += patterns('django.views.static',
(r'^media/(?P<path>.*)$',
'serve', {
'document_root': settings.MEDIA_ROOT,
'show_indexes': True}),)
myapp/views.py
一般情況直接 call views 中的 function 名稱, 但用 HttpResponseRedirect 時就得用 SITE_ROOT, 比方像這樣:
@login_required()
def some_page(request, project_id):
if not request.user.is_staff:
return HttpResponseRedirect(settings.SITE_ROOT)
...
template/*.html
用
url tag, 比方說:
<a href="{% url index %}">Homepage</a>
apache conf
我設在 /etc/apache2/conf.d/MY_DJANGO_CONF.conf。大致設法和 Django 用 mod_wsgi 差不多, 只是改一下路徑:
# Alias other operations to wsgi script.
WSGIScriptAlias /foo FILE_PATH_TO_WSGI_SCRIPT
WSGIScriptAlias /bar FILE_PATH_TO_WSGI_SCRIPT
<Location "/foo/media">
SetHandler None
</Location>
<Location "/bar/media">
SetHandler None
</Location>
Alias /foo/media FILE_PATH_TO_MEDIA
Alias /bar/media FILE_PATH_TO_MEDIA
# 若用 virtualenv 的話就指到 virtualenv 內的 site-packages
Alias /foo/admin_media /usr/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/contrib/admin/media
Alias /bar/admin_media /usr/lib/python2.5/site-packages/Django-1.1.1-py2.5.egg/django/contrib/admin/media
2010-05-06 更新
今天發現要在 JavaScript 內用 AJAX 連線, 於是得在 JavaScript 裡取得 settings.SITE_ROOT, 作法如下:
- 在 settings.py 裡註冊一個 context processor:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth', # 頭四個是預設的, 覆寫 TEMPLATE_CONTEXT_PROCESSORS 時記得加進去
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'mysite.myapp.views.add_constants', # 自己用的
)
- 在 views.py 裡寫 add_constants:
def add_constants(request): return {
'SITE_ROOT': settings.SITE_ROOT,
}
這兩步的目的是讓每個 view 都傳 SITE_ROOT 到 RequestContext 裡。
- 在 template 裡置入 SITE_ROOT 的值, 寫到 base.html 裡:
<script language="javascript" type="text/javascript">
my_app.site_root = '{{ SITE_ROOT }}'; // my_app 是 global object, 作為我的 js code 的 root object
</script>
如此一來, 就能用 my_app.site_root 取得值。
真不是普通的麻煩啊。