bottleでMVC

pythonでデータ解析をしていると、その結果をヴィジュアル的に見せたくなってくる時があります。
PythonのWebフレームワークは様々ありますが、最もシンプルなbottleで作成するのが一番簡単です。

こちらのサイトで、BottleをMVCフレームワーク的に作成されているサンプルがありましたのでちょっといじってみました。その際、ちょっとハマったのでのメモです。

環境

  • OS: ubuntu14.04
  • python: 2.7.6
  • MySQL version: 5.1.63
  • MySQL encode: shift_jis
  • nginx 1.4.6

設定

nginx

http://server/pythonでアクセスできるようにnginxの設定ファイルを修正します

/etc/nginx/site-availables

server {
..

        location /python {
                rewrite ^/python/(.*)$ /$1 break;
                proxy_pass http://localhost:8081;
                proxy_redirect http://localhost:8081/ $scheme://$host/python/;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
                proxy_read_timeout 20d;
        }
..

スクリプト

起動スクリプトを作成します

start.sh

gunicorn -b 127.0.0.1:8081 -c gunicorn.conf.py -w 1 index:app -D --reload  

gunicorn.conf.py

proc_name = "gunicorn"

bind = 'unix:/tmp/{0}.sock'.format(proc_name)
backlog = 2048


workers = 1
worker_class = 'sync'
worker_connections = 1000
timeout = 30
keepalive = 2


debug = False
spew = False

daemon = True
pidfile = "/tmp/gunicorn.pid"
umask = 0
user = None
group = None
tmp_upload_dir = None

errorlog = '/var/log/gunicorn/error.log'
loglevel = 'debug'
accesslog = '/var/log/gunicorn/access.log'


def post_fork(server, worker):
    server.log.info("Worker spawned (pid: %s)", worker.pid)

def pre_fork(server, worker):
    pass

def pre_exec(server):
    server.log.info("Forked child, re-executing.")

def when_ready(server):
    server.log.info("Server is ready. Spawning workers")

def worker_int(worker):
    worker.log.info("worker received INT or QUIT signal")

    ## get traceback info
    import threading, sys, traceback
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""),
            threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename,
                lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    worker.log.debug("\n".join(code))

def worker_abort(worker):
    worker.log.info("worker received SIGABRT signal")

文字化け

上記環境で参考サイトを元に作成すると、DBの文字列を表示する際に文字化けしてしまいます。この対処法は散々悩んだ挙句この修正で行けました

app/models/db.py

dbhandle = MySQLdb.connect(
  host = config.get('live_db', 'host'),
  port = config.getint("live_db","port"), 
  user = config.get('live_db', 'user'),
  passwd = config.get('live_db', 'password'),
  db = config.get('live_db', 'database'),
  charset = "sjis",  # これを追加
  use_unicode=1
)