2012年8月27日 星期一

區別 Django 中的 STATIC_ROOT 與 STATICFILES_DIRS

 

看此篇文章之前,可以先參考

深入了解 django 的 static 設定

 

本文開始

在寫 django 時,我們會引用許多的 app,也會自行製作許多的 app,每一個 app 都可能有自己的 static 檔案或資料夾。

只要在 INSTALLED_APPS 裡引用的 app,便會成為 python manage.py collectstatic 的收集對象,而收集後存放的路徑,便是 STATIC_ROOT

這麼一來便可以讓 app 有自己的 static 資料夾,不需要混在一起了,維護上也會簡單許多。

django default settings.py 裡面 STATIC_ROOT 的上方,也特別警告我們不應該手動更改 STATIC_ROOT 裡面的檔案。

 

有兩個情況我們需要設置 STATICFILES_DIRS

  1. 專案需要一個 static 檔案或資料夾,但卻不知該如何歸類在哪一個 app 底下。
  2. 專案需要改寫某個引用 app 底下的 static 檔案,但卻不希望動到原本 app 底下的 static 檔案。

狀況一我們有待商榷,畢竟「不知該如何歸類」不應該出現在一個成熟的專案下;而狀況二卻很容易發生。

此時便需要設置 STATICFILES_DIRS,越上方的設置優先權越高,而 STATICFILES_DIRS 的優先權當然也高於 INSTALLED_APPS 內的 app

(INSTALLED_APPS 本身也遵循越上方的 app 優先權越高的原則)

admin 舉例

我若要改寫 django/contrib/admin/static/admin/css/base.css,那麼便可如此指定

STATICFILES_DIRS = (
'/project/mystatic',
)

然後建立 /project/mystatic/admin/css/base.css 檔案後編輯,而後下達

python manage.py collectstatic

 

便會將 /project/mystatic/admin/css/base.css 收集到 STATIC_ROOTadmin/css/base.css 底下,並依照優先權決定覆蓋

2012年8月26日 星期日

深入了解 django 的 static 與 media

 

為什麼要設定 static?

為什麼一但設置在 apache 中,static 設定就變得格外重要?開發時,使用 runserver 都不用管這些設定也可以正常運作!

其實那是因為 runserver 是用程式動態決定檔案位置的,如此一來這些 static 檔案,便是參照各「套件」底下的 static 資料夾,而不需要另外設置

作怪的地方在下方,註解起來 runserver 就無法「使用」各套件底下的 static 了(反之應該也可以修改成在 apache 中使用各套件底下的 static,未測試過,也不推薦)

django/contrib/staticfiles/management/commands/runserver.py

image

 

但是為何不能使用 runserver 在正式環境呢?

官方也有提到

https://docs.djangoproject.com/en/dev/ref/django-admin/#runserver-port-or-address-port

DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that's how it's gonna stay. We're in the business of making Web frameworks, not Web servers, so improving this server to be able to handle a production environment is outside the scope of Django.)

 

static 的檔案,讓 django 動態處理,累積起來也是十分浪費效能的,我猜這也是原因之一

 

static 設置說明

在寫 Web 時的路徑非常重要,所以往往因為專案路徑改變而發生悲劇,在 Django 裡,你必須了解以下兩種設置有何不同。(media 觀念亦同)


STATIC_URL = "/static/"

這指的是你的 Template 在撰寫 html 時,所引用的路徑,與 Web Server (如 apache) 的指向息息相關。

所有 Django developer 在撰寫 Template 都會遵守的寫法

<script src="{{ STATIC_URL }}mezzanine/js/jquery.tools.js"></script>

or

<link rel="stylesheet"
type="text/css"
href="{% static "admin/css/login.css" %}" />


PS:兩種寫法在意義上似乎有所不同,有機會研究再發佈一篇文章

 

所以如果使用 apache,那麼上面的設置便會全部指向

[ApacheDocumentRoot]/static/

(如 C:/AppServ/www/static)

 

STATIC_ROOT = "C:/AppServ/www/static/"

這個設置是為了讓 python manage.py collectstatic 知道將 static 檔案收集在哪。

原則上必須與 STATIC_URL 指向的路徑一致,才不會導致與 Web Server 找到的檔案不同

在這個 case 中,就會等於 C:/AppServ/www/static

 

PS:在 apache 的 conf 中,也可以利用 Alias 來轉向,只要設置正確就好

 

STATIC_ROOT 更詳細的說明,可以參考

區別 Django 中的 STATIC_ROOT 與 STATICFILES_DIRS

 

說了這麼多 static,那 media 呢?

mediastatic 不同的地方在於,media 通常是用於放置使用者可新增、編輯、刪除的資料,如上傳的圖片,文件等,除此之外,其餘觀念與 static 的設置沒有什麼不同

Java Applet 在 Client 權限全開的方法

如同 Flash(Flex)、Silverlight…etc在 Client 端執行的程式,Java Applet 在安全性上也有許多限制,原則上只要會占用本地端資源的行為(如開啟socket,存取檔案...等),都是會被拒絕的。

因此必須經過幾個步驟:

  1. 將 Java Applet 程式打包為 jar 檔
  2. 利用 keytool 產生 keystore
  3. 接著再利用 keytool 與此 keystore 產生證書
  4. 最後用 jarsigner 幫 jar 檔加上簽名

 

keytool -genkey -keystore bmcool.store -alias bmcool

keytool -export -keystore bmcool.store -alias bmcool -file bmcool.cert

jarsigner -keystore bmcool.store AppletPolicy.jar bmcool

解決 The _imaging C module is not installed

 

為了搞這個,花了我半天的時間來研究...

在專案中,有一個功能會利用到 PIL 來做縮圖,而 Server 總是回應我

The _imaging C module is not installed

 

但是在 runserver 環境下,都沒有此問題,找了半天,原來是因為官方的 PILmod_wsgi 並不相容。(似乎編譯時連結的函式庫不同,所以無法共用?)

 

最後其實只要把官方的 PIL 移除,改裝這個非官方的 PIL 就可以運作了…

http://www.lfd.uci.edu/~gohlke/pythonlibs/

 

Reference


與本文無關的抱怨

會研究這麼久,是想說應急把 runserver 註冊到 windows service 裡面,結果

  • 要嘛無法進行 Log (使用 os.system 指令)
  • 要嘛無法中斷 (使用 subprocess.Popen 指令)

其實花最多時間研究的,是 subprocess.Popen 如何在 windows 環境下把子程序中斷掉...無法中斷當然也就無法採用這個 solution

以下是程式碼,如果有大德知道如何中斷,麻煩分享分享...


import os
import sys

import win32serviceutil

import subprocess
import time

class service(win32serviceutil.ServiceFramework):
_svc_name_ = 'Django'
_svc_display_name_ = 'Django'
_svc_description_ = 'Django'

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.isAlive = True

def SvcStop(self):
self.isAlive = False

def SvcDoRun(self):
self.timeout = 1000

timestamp = time.localtime()
now = time.strftime("%Y%m%d%H%M%S", timestamp)

outpath = 'C:/AppServ/www/demo/' + now + 'stdout.txt'
errpath = 'C:/AppServ/www/demo/' + now + 'stderr.txt'

with open(outpath, 'wb', 0) as out:
with open(errpath, 'wb', 0) as err:
sub = subprocess.Popen('python C:/AppServ/www/demo/manage.py runserver 0.0.0.0:800', stdout=out, stderr=err)

while True:
if not self.isAlive:
# kill sub here
break

if __name__ == '__main__':
win32serviceutil.HandleCommandLine(service)

在 Windows Service 中註冊 Python Script

 

將自己寫的程式註冊在 Windows Service 中有幾個好處:

  1. 可以在系統啟動時自動啟動。
  2. 可設定程式出了狀況之後的處理機制。(如馬上重啟…etc)
  3. 在多人連線的環境下,常常會限制「登入個數」,也會設定「閒置登出時間」,一但執行程式的 Session 被登出,程式就停止了。

程式碼如下:

service.py


import win32serviceutil

class service(win32serviceutil.ServiceFramework):
_svc_name_ = "ServiceName"
_svc_display_name_ = "Service display name"
_svc_description_ = "Service description"

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.isAlive = True

def SvcStop(self):
self.isAlive = False

def SvcDoRun(self):
self.timeout = 1000
while self.isAlive:
# your script here

if __name__ == '__main__':
win32serviceutil.HandleCommandLine(service)

 

接著只要在命令提示字元下達

python service.py install

 

就可以註冊一個服務到windows裡了

 

其他指令可以下達此命令查詢

python service.py

2012年8月24日 星期五

MySQL 匯入與匯出

 

Quick Note

匯出

mysqldump -u username -p database > backup.sql

 

匯入

mysql -u username -p database < backup.sql

取得 Python 在系統中 Library 的路徑

 

Quick Note:

 

In python

from distutils.sysconfig import get_python_lib
print(get_python_lib())

or

In os shell

python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"

2012年8月16日 星期四

datetime 常用語法

 

Quick Note

 

將字串轉為 datetime 型態(string to datetime)

import time, datetime
timestring = "2005-09-01 12:30:09"
time_format = "%Y-%m-%d %H:%M:%S"
datetime.datetime.fromtimestamp(time.mktime(time.strptime(timestring, time_format)))

 

取得 datetime 的 UNIX timestamp (from 1970)

import time, datetime
 
# eq : now = int(time.time())
now = int(datetime.datetime.now().strftime("%s"))

2012年8月15日 星期三

將 django 內 dateTimeField 的時間轉為本地時間的語法

 

Quick Note

假設已有一個 Model 叫 Poll,裡面有一個叫 create_time 的 DateTimeField

from django.utils import timezone
poll = Poll.objects.all()[0]
poll.create_time.astimezone(timezone.get_current_timezone())

2012年8月13日 星期一

django + haystack + elasticsearch


前言
網路評價,同樣也是全文檢索的 sphinx 在效能上是非常優異的,而 java base 的 lucene 在效能上表現較差。而先前也曾經整合過 sphinxdjango 中。
為何會再研究整合 elasticsearch 主要原因有二:

  • sphinx 採用的授權方式用在商業上有可能會有爭議
  • 由於 haystack 的支援,對 django 的整合性非常高
  • 至於效能的議題,或許等資料量真的大到某個程度後再來煩惱也不遲。(尤其 sphinx 的 reindex 速度如此之快,到時再派它出馬也行…)

    事前準備
    請先閱讀ec2(ubuntu12.04) + django + apache + mysql + scrapy + sfc(sphinx) 安裝
    重複的步驟便不在贅述,主要是把 sfc 換成 haystack + elasticsearch

    安裝步驟
    安裝 elasticsearch(參考 https://gist.github.com/2026107)
    apt-get install openjdk-7-jre -y

    wget https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.19.8.tar.gz -O elasticsearch.tar.gz
    tar -xf elasticsearch.tar.gz
    rm elasticsearch.tar.gz
    mv elasticsearch-* elasticsearch
    mv elasticsearch /usr/local/share

    curl -L http://github.com/elasticsearch/elasticsearch-servicewrapper/tarball/master | tar -xz
    mv *servicewrapper*/service /usr/local/share/elasticsearch/bin/
    rm -Rf *servicewrapper*
    /usr/local/share/elasticsearch/bin/service/elasticsearch install
    ln -s `readlink -f /usr/local/share/elasticsearch/bin/service/elasticsearch` /usr/local/bin/rcelasticsearch


    EC2 micro 規格較差,需將 ES_HEAP_SIZE 改為 256 (or 512) 才有辦法跑起來,所以需要調整 configure 檔案,更動檔案最上方兩行

    vi /usr/local/share/elasticsearch/bin/service/elasticsearch.conf
    set.default.ES_HOME=/usr/local/share/elasticsearch/ set.default.ES_HEAP_SIZE=256

    啟動 elasticsearch
    service elasticsearch start

    透過 curl 測試
    curl http://localhost:9200
    {   "ok" : true,   "status" : 200,   "name" : "Mammomax",   "version" : {     "number" : "0.19.8",     "snapshot_build" : false   },   "tagline" : "You Know, for Search" }
    安裝 haystack
    (假設已經安裝好 django/mysql 等相關環境)
    apt-get install git
    pip install -e git+https://github.com/toastdriven/django-haystack.git@master#egg=django-haystack
    cd src/django-haystack/
    python setup.py install
    cd ~
    rm -r src

    安裝其他相關套件
    pip install requests

    pip install -e git+git://github.com/toastdriven/pyelasticsearch.git@master#egg=pyelasticsearch
    cd src/pyelasticsearch/
    python setup.py install
    cd ~
    rm -r src

    設定資料庫
    mysql -u root –p
    CREATE DATABASE HaystackSearch default character set utf8mb4;
    exit

    建立 Django 專案
    自行建立一個專案可參考
    http://django-haystack.readthedocs.org/en/latest/tutorial.html

    採用我已經建立好的專案(主要以上面教學為主進行操作)
    上傳 HaystackSearch 資料夾至 /root/
    (需設定 mysql 帳號密碼)

    cd ~/HaystackSearch
    python manage.py runserver 0.0.0.0:80

    http://[EC2_IP]/admin/HaystackSearch/note/add/
    新增幾筆後,下達
    python manage.py update_index

    接著就可以在底下頁面測試搜尋的結果了
    http://[EC2_IP]/search

    2012年8月7日 星期二

    ec2(ubuntu12.04) + django + apache + mysql + scrapy + sfc(sphinx) 安裝


    前言
    對一般人來說,比較陌生的是:

    • scrapypython 的爬蟲套件
    • sfc(sphinx) – Sphinx For Chinese 基sphinx 全文檢索套件,並加上中文分詞的支援。(本來打算用 coreseek,但似乎用在繁體中文會有問題,需另外花錢請 coreseek 研發團隊制定) 這是一篇基於 django 安裝搜尋引擎環境的文章。
    事前準備
    我假設你已經熟悉以下相關知識:
    • AWS EC2(Ubuntu)
    • django

    安裝步驟
    登入EC2後,首先進行 apt-get 的更新
    apt-get update
    apt-get upgrade

    EC2 本身就會 default 安裝好 python 2.7.3,因此只要直接安裝 pip 以及 virtualenv 即可
    安裝 pip
    apt-get install python-pip

    安裝 virtualenv
    apt-get install python-virtualenv

    建立虛擬環境
    之後便利用 virtualenv 建立一個虛擬環境給 django,使後續安裝的 python 元件獨立於系統 python 的函式庫外。(此步驟非必須,只是這樣可以建立乾淨的環境)
    virtualenv ./djangoenv

    將環境切換至 djangoenv 虛擬環境
    source ./djangoenv/bin/activate

    安裝 django(目前最新的版本是 1.4.1)
    pip install django

    安裝 scrapy
    要安裝 scrapy 之前,必須先安裝 gcc 以及編譯相關套件
    apt-get install python-dev
    apt-get install build-essential
    apt-get install libxml2-dev
    apt-get install libxslt-dev

    接著安裝 scrapy
    pip install scrapy

    安裝 mysql
    apt-get install mysql-server
    此步驟會進行mysql root 的帳號設定

    apt-get install libmysqlclient-dev
    apt-get install mysql-client
    pip install mysql-python



    安裝 sfc
    wget http://sphinx-for-chinese.googlecode.com/files/sphinx-for-chinese-2.0.2-beta-r3019.tar.gz
    tar zxvf sphinx-for-chinese-2.0.2-beta-r3019.tar.gz
    cd sphinx-for-chinese-2.0.2-beta-r3019/
    ./configure --prefix=/usr/local/sphinx --with-mysql
    make & make install
    cd ~

    設置環境變數
    vi ~/.bashrc

    在最底下加上(~/.bashrc 是每個使用者登入都會執行的一個 sh 檔,通常用來宣告環境參數)
    PATH="/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/local/sphinx/bin/"
    PATH="$PATH":/usr/X11R6/bin:/home/dmtsai/bin
    LANG=zh_TW.big5

    reboot

    重新登入後,一樣切換到 djangoenv 底下
    source ./djangoenv/bin/activate

    確認是否有成功
    echo $LANG
    => zh_TW.big5

    下載 & 安裝中文字庫(未來新增字詞就是反覆操作此步驟)
    wget http://sphinx-for-chinese.googlecode.com/files/xdict_1.1.tar.gz
    tar zxvf xdict_1.1.tar.gz
    mkdict xdict_1.1.txt xdict
    mv xdict /usr/local/sphinx/etc/

    產生出來的 xdict 檔案便是未來定義 sphinx.conf 檔案時,chinese_dictionary 參數所需指向的路徑(如 chinese_dictionary = /usr/local/sphinx/etc/xdict )
    若要新增字詞,則可編輯 xdict_1.1.txt 檔案後,重新執行底下的指令即可
    mkdict xdict_1.1.txt xdict

    安裝 django-sphinx
    pip install django-sphinx

    設定 sfc
    下載檔案
    壓縮檔內的檔案分別是:
    • dstest – django 的 sfc test application (需開啟 settings.py 設定資料庫帳密)
    • scrapytest – scrapy 的 test application
    • build_main_index.sh - 更新 index 的腳本 / 清除 sphinx log
    • sphinx.conf – sphinx 的設定檔 (需開啟設定資料庫帳密)

    解壓縮上傳之後
    mv sphinx.conf /usr/local/sphinx/etc
    mv build_main_index.sh /usr/local/sphinx/bin/
    chmod +x /usr/local/sphinx/bin/build_main_index.sh

    設置 crontab 每30分鐘重新建立一次索引
    crontab -e
    0-57/30 * * * * /bin/sh /usr/local/sphinx/bin/build_main_index.sh

    增加開機程序,主要使 searchd 不用每次都人工開啟
    vi /etc/rc.local
    在檔案最下方增加 (exit 0 之上)
    ulimit -SHn 500000
    /usr/bin/nohup /bin/sh /usr/local/sphinx/bin/build_main_index.sh 2>&1 > /dev/null &
    /usr/local/sphinx/bin/searchd

    如此一來便大功告成

    測試 sphinx
    將上面壓縮檔裡的 dstest 與 scrapytest 都放置在 /root/ 底下
    mysql -u root -p
    CREATE DATABASE dstest default character set utf8;
    exit

    cd ~/dstest/
    python manage.py syncdb
    python manage.py runserver 0.0.0.0:80
    然後進入到 admin 介面增加幾筆資料

    接著下達底下指令建立索引
    indexer --all

    打開 searchd
    searchd

    打開瀏覽器,輸入
    http://[EC2_IP]/search/

    就可以看到搜尋畫面,並可以搜尋剛剛建立的資料(default 是全部的資料)

    測試 scrapy
    cd ~/scrapytest/

    下達底下指令就會開始爬文,並存入 mysql db dstest 中 model 的資料表裡
    scrapy crawl scrapytest

    都沒看到錯誤訊息就算是成功了,接著可以到後台看是否有資料匯入(但資料我是亂抓的,沒經過處理,所以看起來會很像亂碼)

    若要把爬過的資料也納入搜尋中,可執行
    indexer --rotate --all

    安裝 apache
    apt-get install apache2
     
    安裝 mod_wsgi
    mod_wsgi 可使 Apache 支援 python 的應用程式,據網路評價,在表現上比 mod_python 還優異許多,底下是官方網站
    http://code.google.com/p/modwsgi/
    apt-get install libapache2-mod-wsgi
     
    設定 django + apache
    (記得先停用 python manage.py runserver)
    NOTE:
    /etc/apache2/sites-available
    這裡放的是可用但不一定啟用的設定檔,需透過 a2ensite, a2dissite 指令啟停
     
    /etc/apache2/sites-enabled
    這裡放的是會自動啟用的設定檔,若設定上有衝突,從檔名排序小的優先
    (如都佔用了 VirtualHost *:80)
    

    先開啟 /root/ 資料夾權限,讓 apache 可存取
    chmod 777 /root
     
    cd /etc/apache2/sites-enabled
    mv 000-default 999-default
    vi 000-dstest

    貼上底下的內容
    <VirtualHost *:80>
            WSGIScriptAlias / /root/dstest/dstest/wsgi.py
            Alias /static /root/djangoenv/lib/python2.7/site-packages/django/contrib/admin/static
    </VirtualHost>


    因使用 virtualenv,所以 dstest/dstest/wsgi.py 也做了些修改,在最上方加入
    import sys
    import site

    site.addsitedir('/root/djangoenv/lib/python2.7/site-packages')
    sys.path.append('/root/dstest')


    重啟apache
    /etc/init.d/apache2 restart

    打開瀏覽器,輸入
    http://[EC2_IP]/admin/

    就可以看到 admin 頁面,完成了所有設定。
     
     
    注意事項:
    Alias /static /root/djangoenv/lib/python2.7/site-packages/django/contrib/admin/static
    這行只是暫時的解法,未來應該要在適合的地方建立 django 的 static 資料夾以及 media 資料夾,並用上述的方法分別設置。
    設置後也需記得將 /root/djangoenv/lib/python2.7/site-packages/django/contrib/admin/static/admin 資料夾複製到你設置的 static 底下)
     
    Reference:

    Amazon EC2 使用密碼登入(不用 pem 檔案)

    Quick Note
    1. 正常方式登入 EC2(use ssh –i xxxx.pem)
    2. sudo vi /etc/ssh/sshd_config
    3. 將 PasswordAuthentication 改成 yes 後存檔
    4. sudo passwd root - 設置 root 密碼
    5. sudo reboot
    補充

    2012年8月6日 星期一

    用 Tcl 實作 BBS Client - TclTelnet

    SNAGHTML2f9694

    前言

    PTT 已經是台灣最重要的資訊交流地之一,不管是美食、O2、八卦、表特…等,在這邊都可以找到許多資源。但若用PCMAN、KKMAN等telnet軟體連線,都只能人工看,無法做到自動觀察的行為。

    (如果有[徵男]出現,當然要第一時間看文章,做出回應呀!)

     

    Github 連結

    https://github.com/bmcool/TclTelnet

     

    安裝方式

    與一般 Tcl package 無異,解壓縮至 Tcl/lib 底下即可。

     

    使用範例

    package require TclTelnet
     
    # New 一個 TclTclnet 物件 telnet
    ::TclTelnet::TclTelnet telnet
     
    # 進行連線
    telnet connect ptt.cc
     
    # 送出 myusername 字元,並按下 Enter
    telnet sendLine myusername
     
    # 送出 myusername 字元,並按下 Enter
    telnet sendLine mypassword
     
    # 按下「上」
    telnet press up
     
    # 取得畫面 80 x 24 的字串
    telnet printScreen
     

    其他更詳細的 method 可以直接閱讀 TclTelnet.xotcl