Cody Blog

Software development

使用 south 來做 Django database migration

一般在 Django 底下更動 model 的時侯,必須使用 syncdb 這個指令,把修改的 model 同步到 database 之中,但是有個限制,就是只有新的 model 才會被更新,已經存在的 model 就不會更動,此時就需要south的幫忙。在 django 1.7 之後,這個 library 正式被整進到 django 之中。不過目前我手頭上的專案還是以 1.6 為主,所以還是要筆記一下。

初始化 south

安裝完 south 之後,第一次先執行 syncdb 把 south 相關的south_migrationhistory 新增到資料庫中。

:::console
$ ./manage.py syncdb

開始 migration

首先要介紹的是 schemamigration <APP_NAME> --initial,這個指令會在 app 資料夾下面產生一個 migrations 資料夾。如果是第一次執行的話,裡面的檔名會是 0001_initial.py 開頭,裡面會記錄如何從無到有,把資料表建立起來。

:::python
def forwards(self, orm):
    # Adding model 'UserModel'
    db.create_table(u'dusers_dmodel', (
        (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),

此時可以執行 syncdb 做一下確認

:::console
$ python ...

使用 Pyenv 管理多個 Python 版本

pyenv 是一個 Python 版本管理器,也可以安裝 pyenv-virtualenv 達來支援 virtualenv 的功能。

安裝 pyenv 和 pyenv-virtualenv

:::console
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
$ git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
$ sudo pip install virtualenv

In Ubuntu:

$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm

Or, 使用yyuu/pyenv-installer

把下列加到 ~/.bashrc

:::console
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

安裝其它版本的 Python

查看可供安裝的 python 版本

:::console
$ pyenv install -l
...
3.4.0
3.4.1
3.4-dev
...

如果想要裝 3.4.1 的話,就使用pyenv install

:::console
$ pyenv ...

在Python中如何Async的方式呼叫外部程式

最近有個需求:使用Python呼叫外部程式,外部程式屬於背景程式類型。也就是我希望python程式結束時不需要等待外部程式結束。Google了一下,找到Stack Overview的解答,關鍵就是在 subprocess.popen() 使用 creationflags 這個參數,這個方法只有在Windows試驗過,其它的平台就不確定了。比如說我想呼叫notepad:

:::python
import subprocess
DETACHED_PROCESS = 0x00000008
subprocess.Popen(["notepad"], shell=True, close_fds=True, creationflags=DETACHED_PROCESS)

這樣這支python程式就會自行結束,而不會等notepad了。

Reference :

[Python] Class Private 跟 Module Private 的差別

在Python中雖然有Private variable,但是不像一般程式語言一樣具有強制的效力,如果外界執意要使用還是可以呼叫的到。在這篇StackOverflow有很清楚的解釋其中的差別。

  • Module private 是指是以一個下底線 _ 開頭的變數,例如 _number 或 _getNumber() 

  • Class Private 基本上是以二個下底線 __ 開頭,而且不超過一個下底線 _ 結尾的的變數名稱,例如 __number 或 __getNumber(),但是init 就不是 class private,但這種兩個下底線開頭和結尾叫 Magic methods有其特別的用途,但這個不在本文討論範圍。

Module Private

# moduleA.py

def _foo():
    return 'hi'

from moduleA import *
    print _foo()

以此例子來說,我們在 moduleA.py裡面定義了一個 Module private _foo(),因為Python有個規定是在Import的時侯會略過所有以underscore開頭的成員,所以_foo()會被忽略,在執行 print _foo() 的時侯就會發生 Exception:

Traceback (most recent call last):
File "D:\priavte\__init__.py", line 4, in <module>
NameError: name '_foo' is not defined

但是如果執意要用還是可以透過Import __foo,得到想要的結果

from moduleA  import _foo
print _foo()

Class Private

class Foo():
    __aoo ...

Python 多種 Print 函式的用法

最簡單的用法:把想Print的內容放在 print 後面

print 'Hello'

輸出結果

Hello

另一個方便的用法,可以把不同資料型態的變數不經過轉型就直接一起print出來:

print 'Hello',2012

也就是可以省下把其它變數都轉成string的麻煩

輸出結果

Hello 2012

想把多個 print 合併在同一行輸出,而不要一個print就斷行一次,就在最後面加上一個逗號:

print 'Execution Result:',
print runSomeThing()

輸出結果:

Execution Result: PASS

另外低階的sys.stdout.write在特定需求也可以使用,比如說我想輸出兩個字串,但是中間不要像 print 函式一樣加一個空白的話,就可以使用這個方法:

import sys
sys.stdout.write("Hello")
sys.stdout.write("2012")

輸出結果:

Hello2012