Archive@2007/08

MacのDjangoをsvn-trunkに。

Macの Django を0.96からsvn-trunkにしてみたメモ。

とりあえずは svn でソースを落としてくる。 どこに置いても良いみたいなので、今回は /usr/local/src/Django に置いた。

$ cd /usr/local/src
$ svn co http://code.djangoproject.com/svn/django/trunk ./Django

落として来たソースの中にある django なディレクトリを、 シンボリックリンクとかで site-packages に入れてやれば良いらしい。 ので、既存の Django - 0.96と置き換える形になる。

$ cd /usr/local/python/lib/python2.5/site-packages
$ sudo rm -rf ./django
$ sudo rm Django-0.96-None-py2.5.egg-info
$ sudo ln -s /usr/local/src/Django/django ./django

ココでひとまずバージョン確認しておく。

>>> import django
>>> django.VERSION
(0, 97, 'pre')

とりあえずは上手く行っている模様。 まぁ、転ぶところなんて無い訳ですが。

で、エラー吐くと分かっていながらも、 ブログのソースを runserver してみる。

$ ./manage.py runserver
Validating models...
0 errors found

Django version 0.97-pre-SVN-6022, using settings 'applications.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

意外にも素直に立ち上がってくれた。 じゃあ、って事で意気揚々とブラウザから確認。

が、しかし。

Exceptionが飛んでる。 LookupError だそうです。 unknown encoding: X-MAC-JAPANESE らしく、完全にMac固有の問題っぽい。 どうやら locale モジュールの getdefaultlocale が悪さ?をしてるらしく、 インタラクティブシェルで確認してみる。

>>> import locale
>>> locale.getdefaultlocale()
(None, 'X-MAC-JAPANESE')

ちなみにコイツ、言語環境で英語に切り替えて試すと mac-roman に変わった。 それだと Django は元気よく動いてくれた。 けど、環境ほぼ全てが英語になってしまう。それはちょっと犠牲多過ぎ。

ちょっとGoogleさんに相談してみるといくつか情報を発見。

まずは1個目方法を試す。と、ちゃんと動く。 なるほど、目指す場所は理解出来た気がする。

2個目の方法は getdefaultlocale ではないものの、 たぶん根っこの部分は同じだと思う。という勝手な思い込み。 別のライブラリとかで同じエラーに出くわすのもアレなので、 今回はこちらの方法で対処する事にした。

具体的には Python ソースツリーの Modules/_localemodule.c に以下を追記してリコンパイル。 これで良いのかは分かりませんけれども。

static char *mac_getscript(void)
{
    CFStringEncoding enc = CFStringGetSystemEncoding();
    static CFStringRef name = NULL;
    /* Return the code name for the encodings for which we have codecs. */
    switch(enc) {
    case kCFStringEncodingMacRoman: return "mac-roman";
    case kCFStringEncodingMacGreek: return "mac-greek";
    case kCFStringEncodingMacCyrillic: return "mac-cyrillic";
    case kCFStringEncodingMacTurkish: return "mac-turkish";
    case kCFStringEncodingMacIcelandic: return "mac-icelandic";
    /* ココを追加 */
    case kCFStringEncodingMacJapanese: return "utf-8";
    /* XXX which one is mac-latin2? */
    }
    if (!name) {
        /* This leaks an object. */
        name = CFStringConvertEncodingToIANACharSetName(enc);
    }
    return (char *)CFStringGetCStringPtr(name, 0);
}

リコンパイル後にもう一度インタラクティブシェルでテスト。

>>> import locale
>>> locale.getdefaultlocale()
(None, 'utf-8')

上手くいったっぽい! Django もちゃんと動いたしね! でも、ちょっと疲れたので UbuntuDjango アップデートはまた今度。

追記

X-MAC-JAPANESE に一番近いのはshift_jisだそうです。なので、utf-8を返すのは間違い。詳しくは Django-ja (at Lingr) > Archives > September 07, 2007 をご覧ください!

今後、気をつけます。

Posted at: 
2007/08/27 19:24:07
0 Comments
0 TrackBacks
Tags: 
Django
Mac
Python
Trackback: 
http://humming.via-kitchen.com/2007/08/27/update-django-on-mac/trackback/

SQLAlchemyで遊んでみる。その2

SQLAlchemyで遊んでみる。その1 の続き。

今回は SELECT のやり方をちょくちょく試してみたよ。 まぁ、前回同様ドキュメントに従ったり従わなかったりはその場の気分でやっております。

テーブル定義とかは前回のものをそのまま使った。 ので、とりあえずはインポートする。 ただ、データは新しく作り直す事にした。

>>> import sha
>>> from tutorials import *

>>> # 一度テーブルを全部ドロップする。
>>> meta.drop_all(checkfirst=True)

>>> # テーブル作成。
>>> meta.create_all(checkfirst=True)

Session オブジェクトを作って、新しくデータを登録していく。

>>> # Sessionクラスを作る。
>>> Session = sessionmaker(autoflush=True, transactional=True)

>>> # Sessionクラスのインスタンス化。
>>> sess = Session()

>>> # とりあえず10個テストデータを作る。
>>> for i in range(10):
...    a = 'test%s' % (i + 1)
...    sess.save(User(a, sha.new(a).hexdigest()))

>>> # ココでコミット。
>>> sess.commit()

何も考えず全部取り出すならこんな感じになるらしい。

>>> sess.query(User).all()
2007-08-27 02:21:08,185 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:21:08,186 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>,
 <User('test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f')>,
 <User('test3', '3ebfa301dc59196f18593c45e519287a23297589')>,
 <User('test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b')>,
 <User('test5', '911ddc3b8f9a13b5499b6bc4638a2b4f3f68bf23')>,
 <User('test6', 'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User('test7', 'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User('test8', 'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User('test9', '53d525836cc96d089a5a4218b464fda532f7debe')>,
 <User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>]

>>> # コレでもいける。
>>> for row in sess.query(User):
...    print row
2007-08-27 02:22:33,576 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:22:33,577 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>
<User('test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f')>
<User('test3', '3ebfa301dc59196f18593c45e519287a23297589')>
<User('test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b')>
<User('test5', '911ddc3b8f9a13b5499b6bc4638a2b4f3f68bf23')>
<User('test6', 'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>
<User('test7', 'ea3243132d653b39025a944e70f3ecdf70ee3994')>
<User('test8', 'd03f9d34194393019e6d12d7c942827ebd694443')>
<User('test9', '53d525836cc96d089a5a4218b464fda532f7debe')>
<User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>

特定のデータを取り出すのにインデクシングしてみる。

>>> # 最初だけ取り出す。
>>> sess.query(User)[0]
2007-08-27 02:23:20,282 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT 1 OFFSET 0
2007-08-27 02:23:20,283 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>

>>> # 最後だけ取り出す。
>>> sess.query(User)[-1]
2007-08-27 02:25:15,941 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:25:15,942 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<type 'exceptions.IndexError'>: list index out of range
>>> sess.query(User)[-2]
2007-08-27 02:26:05,141 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:26:05,142 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>

最後のデータを取り出すのにちょっと癖があるみたい。 しかも、最後のデータを取り出す形だと LIMIT, OFFSET が付かないらしい。 まぁ、可変長のデータに対してデータ取得前に長さが分かるはずないから当然だとは思う。

次にスライシングもやってみる。

>>> # 適当な範囲指定。
>>> sess.query(User)[1:5].all()
2007-08-27 02:30:12,270 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT 4 OFFSET 1
2007-08-27 02:30:12,270 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User('test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f')>,
 <User('test3', '3ebfa301dc59196f18593c45e519287a23297589')>,
 <User('test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b')>,
 <User('test5', '911ddc3b8f9a13b5499b6bc4638a2b4f3f68bf23')>]

>>> # あえて範囲外を指定してみる。
>>> sess.query(User)[5:20].all()
2007-08-27 02:31:09,289 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT 15 OFFSET 5
2007-08-27 02:31:09,290 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User('test6', 'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User('test7', 'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User('test8', 'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User('test9', '53d525836cc96d089a5a4218b464fda532f7debe')>,
 <User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>]

>>> # リミットをマイナス値指定。
>>> sess.query(User)[5:-2]
2007-08-27 02:33:32,609 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:33:32,609 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User(u'test6', u'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User(u'test7', u'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User(u'test8', u'd03f9d34194393019e6d12d7c942827ebd694443')>]
>>> sess.query(User)[5:-1]
2007-08-27 02:35:16,456 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:35:16,456 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User(u'test6', u'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User(u'test7', u'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User(u'test8', u'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User(u'test9', u'53d525836cc96d089a5a4218b464fda532f7debe')>]
>>> sess.query(User)[5:].all()
2007-08-27 02:37:55,613 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT -1 OFFSET 5
2007-08-27 02:37:55,616 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User(u'test6', u'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User(u'test7', u'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User(u'test8', u'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User(u'test9', u'53d525836cc96d089a5a4218b464fda532f7debe')>,
 <User(u'test10', u'168f4029f416ee06565f12e697dfc1534ae69d32')>]

インデクシングとスライシングとでリミットの挙動が違うのがちょっと気になる。 そんなものなのかなぁ?どうだろう?

細かいところが気になって全然進まないけど、継続して色々試していこう。 SQLを遅延評価してくれるところはかなり素敵。 all が付いたり付かなかったりしてるのもそのためっす。

Posted at: 
2007/08/27 02:53:46
0 Comments
0 TrackBacks
Tags: 
Python
SQLAlchemy
Trackback: 
http://humming.via-kitchen.com/2007/08/27/play-with-sqlalchemy-part2/trackback/

jQuery-1.1.4が出たよ。

jQuery - 1.1系最後のリリースとなる(のか?)1.1.4が出たよ!

今回もかなりのスピードアップが計られたみたいなのですが、 それに加えて新しいメソッドやセレクタも追加されたみたい。

詳しい内容は jQuery 1.1.4: Faster, More Tests, Ready for 1.2 で確認出来る。

やっぱ jQuery - 1.2 が9月に出るって事もあってか、かなり変更がかかってる模様。 jQuery.extend が再帰的マージに対応したトコとかはかなり素敵。 JSON の処理とか、デフォルト値の設定とかがかなり楽になりそう。

eq, lt, gtslice にまとめられてすっきりすると思う。 もともとメソッドとしては殆ど使わなかったし(セレクタとしては重宝)。

が、しかし。 $(a[@href])deprecated ってのはかなりイタイ。 $(a[href]) に変更になるらしいけど、ソースの修正がかなり出てきそう。

このまま jQuery - 1.2まで座して待つか、それとも 1.1.4入れて修正しておくか、正直かなり迷う。 Django - 0.97が同じタイミングで出てくれれば、一気に修正するっていう選択肢が出て来て、 モチベーションあげれるんだけどなぁ。

Posted at: 
2007/08/25 02:54:13
0 Comments
0 TrackBacks
Tags: 
JavaScript
jQuery
Trackback: 
http://humming.via-kitchen.com/2007/08/25/jquery-114-release/trackback/

SQLAlchemyで遊んでみる。その1

前からちょくちょく弄っている SQLAlchemy なのですが、 ようやく 0.4(beta4) になったのでちょっと本腰入れて触ってみようと。 色々変わったところとかもあるみたいなので、 とりあえずもう1回ドキュメントを見ながら触ってみる。 って言いつつ、そのままやっても面白くないのでドキュメント半分・適当半分な訳ですが。

インストールは easy_install 経由で行った。 これが正しいのかは分からないけど。まぁ、入ったので良しとする。

$ sudo easy_install http://pypi.python.org/packages/source/S/SQLAlchemy/SQLAlchemy-0.4.0beta4.tar.gz#md5=97b00cfba5bcb7cc947320a66c2ce085

で、ドキュメントに書いてある通りにバージョン確認。

>>> import sqlalchemy
>>> sqlalchemy.__version__
'0.4.0beta4'

とりあえずインストールは上手くいってる模様なので、 ドキュメントを読み進めていく。 ココから復習・勉強スタート。

まずは engine 作って MetaData 作って。 ここらへんはインタープリタでやって誤字・脱字すると過激にやる気無くすので、 ファイルに書いてインポートする事に。 0.4からは ORM に関連する部分が sqlalchemy.orm に分かれたらしく、 基盤部分?とは別々にインポートする形になっているみたい。

# vim: fileencoding=utf-8 :

from datetime import datetime
from sqlalchemy import *
from sqlalchemy.orm import *


# 実行されたSQLを確認するためにecho=Trueにしておく。
engine = create_engine('sqlite:///tutorial.db', echo=True)

meta = MetaData(bind=engine)


# usersテーブルの定義。
users = Table('users', meta,
    Column('id', Integer, primary_key=True),
    Column('name', String(40), nullable=False),
    Column('password', String(40), nullable=False),
    Column('created_at', DateTime, nullable=False, default=datetime.now),
    Column('updated_at', DateTime, nullable=False, default=datetime.now, onupdate=datetime.now),
)


# usersのドメインオブジェクト作成。
class User(object):
    def __init__(self, name=None, password=None):
        self.name = name
        self.password = password

    def __repr__(self):
        return "<User(%r, %r)>" % (self.name, self.password)


# Userとusersの関連づける。
mapper(User, users)

コレをインタープリタで読み込む。 とりあえずデータベースへテーブル作成。

>>> # さっき作成したファイルのインポート。
>>> from tutorials import *

>>> # データベースへテーブル作成。
>>> meta.create_all()
2007-08-23 23:24:53,511 INFO sqlalchemy.engine.base.Engine.0x..b0 PRAGMA table_info("users")
2007-08-23 23:24:53,512 INFO sqlalchemy.engine.base.Engine.0x..b0 {}
2007-08-23 23:24:53,518 INFO sqlalchemy.engine.base.Engine.0x..b0
CREATE TABLE users (
        id INTEGER NOT NULL,
        name VARCHAR(40) NOT NULL,
        password VARCHAR(40) NOT NULL,
        created_at TIMESTAMP NOT NULL,
        updated_at TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)


2007-08-23 23:24:53,519 INFO sqlalchemy.engine.base.Engine.0x..b0 None
2007-08-23 23:24:53,529 INFO sqlalchemy.engine.base.Engine.0x..b0 COMMIT

ORMを操作する為には Session オブジェクトが必要なので作成する。

>>> Session = sessionmaker(bind=engine, autoflush=True, transactional=True)

>>> # この段階ではSessionクラス
>>> Session
<class 'sqlalchemy.orm.session.Sess'>

>>> # ココでインスタンス化
>>> sess = Session()
>>> sess
<sqlalchemy.orm.session.Sess object at 0x16c38d0>

ココで適当にUserオブジェクトを作成してみる。 パスワードを無駄にハッシュ化する為に sha もインポートしておく。

>>> import sha
>>> u1 = User('test1', sha.new('test1').hexdigest())
>>> u1
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>

>>> # ココではまだデータベースへは登録されない。
>>> sess.save(u1)

>>> # ココでデータベースにアクセス
... # 一緒にINSERT文も走っているがコミットはされてない。
>>> sess.query(User).filter_by(name='test1').first()
2007-08-23 23:53:29,697 INFO sqlalchemy.engine.base.Engine.0x..f0 BEGIN
2007-08-23 23:53:29,751 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-23 23:53:29,752 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac', '2007-08-23 23:53:29.741694', '2007-08-23 23:53:29.741829']
2007-08-23 23:53:29,787 INFO sqlalchemy.engine.base.Engine.0x..f0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users
WHERE users.name = ? ORDER BY users.oid
 LIMIT 1 OFFSET 0
2007-08-23 23:53:29,789 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test1']
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>

>>> # u1のidを確認してみる。
>>> u1.id
1

ドキュメント通りにたくさん作成していく。

>>> sess.save(User('test2', sha.new('test2').hexdigest()))
>>> sess.save(User('test3', sha.new('test3').hexdigest()))
>>> sess.save(User('test4', sha.new('test4').hexdigest()))
>>> u1.password = sha.new('test1new').hexdigest()

>>> # ココでコミットをコール。
>>> sess.commit()
2007-08-24 00:04:40,053 INFO sqlalchemy.engine.base.Engine.0x..f0 UPDATE users SET password=?, updated_at=? WHERE users.id = ?
2007-08-24 00:04:40,053 INFO sqlalchemy.engine.base.Engine.0x..f0 ['2eecc02dc033e0aa85cd7a116626136bf4067d85', '2007-08-24 00:04:40.52547', 1]
2007-08-24 00:04:40,060 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-24 00:04:40,061 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f', '2007-08-24 00:04:40.60324', '2007-08-24 00:04:40.60424']
2007-08-24 00:04:40,072 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-24 00:04:40,074 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test3', '3ebfa301dc59196f18593c45e519287a23297589', '2007-08-24 00:04:40.72284', '2007-08-24 00:04:40.72385']
2007-08-24 00:04:40,080 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-24 00:04:40,082 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b', '2007-08-24 00:04:40.80366', '2007-08-24 00:04:40.80466']
2007-08-24 00:04:40,089 INFO sqlalchemy.engine.base.Engine.0x..f0 COMMIT

もうちょっと試したいけど、とりあえずココまで。 次は Query とかセレクトで遊ぶ予定。

Posted at: 
2007/08/24 00:27:02
0 Comments
0 TrackBacks
Tags: 
Python
SQLAlchemy
Trackback: 
http://humming.via-kitchen.com/2007/08/24/play-with-sqlalchemy-part1/trackback/

vimでsnippet

最近 vim を使う事が何かと多くなってきてるのですが、 今まで TextMate を使って来てたのもあって、HTMLとか書く時結構ツライ。

何か良いプラグイン無いかな?と探してみたら snippetsEmu ってプラグインを発見!

これ、拡張子が .vba だけど、どうやって入れるの?と思ってた矢先に ZeroMemory さんの コチラのエントリー を見つけた。ので、これに従ってインストールしてみる。

そう言えば、 snippetsEmu のページに $HOME/.vim/after/ftplugin なディレクトリを作ってからインストールしてね。みたいな事が書いてあったので、まずは作っておく。

$ mkdir ~/.vim/after
$ mkdir ~/.vim/after/ftplugin

で、落として来た snippetsEmu.vbavim で開いて以下を実行。

:source %

なんか見慣れないアラートみたいなのが画面いっぱいに表示される。 画面下に more な文字が出ているのでとりあえず最後まで見る。(コレを途中で止めるとインストールも途中で止まっちゃう!)

後は .vimrc に一行追加しておしまい。

filetype plugin on

適当にHTMLなファイル開いて doctype<TAB> とかやるとDOCTYPE宣言が補完されます。他にもたくさんあって、 TextMatesnippet さながらの動きをしてくれます。素敵。

デフォルトだと余計なものまで吐いたり、ちょっと気持ち悪かったりしたので、 $HOME/.vim/after/plugin の中にあるファイルを修正して回避。使っていくうちに自分で拡張していけばかなり感じになりそう。

vim7 required なので、インストールする前にご確認を。

Posted at: 
2007/08/12 17:34:11
0 Comments
0 TrackBacks
Tags: 
plugin
vim
Trackback: 
http://humming.via-kitchen.com/2007/08/12/snippet-on-vim/trackback/

PrivatePortfileでvim入れたよ

PrivatePortfilevim 入れたよ。 gvim 使ってみたかったし、アンチエイリアスとか文字がキレイだとテンションが上がるのです。

実際に入れたのはこの2つ。

vim のvariantで +migemo とかすると PrivatePortfile/CMigemo に依存するらしい。

とりあえずは両方ダウンロードしてきて、 LocalPortfile のツリーに入れる。で、ツリーを更新しておく。

# LocalPortfileのトップで叩く。
$ sudo portindex

一度 search してみて確認する。

$ port search migemo
cmigemo                        textproc/cmigemo 1.3c         C/Migemo is a Japanese incremental search tool.

vim も確認。

$ port search vim
vim                            editors/vim    7.1.54       Vi workalike with many additional features
vimdrop                        aqua/vimdrop   0.8          droplet for getting files loaded into vim
vim                            editors/vim    7.1.050      Vi workalike with many additional features
vim-app                        editors/vim-app 7.1.050      Vim.app is a GUI version of the famous editor vim.
p5-text-vimcolor               perl/p5-text-vimcolor 0.11         syntax color text in HTML or XML using Vim.
vim2html                       textproc/vim2html 1.46         vim2html converts any Vim-editable file into well-formed HTML

vim に関しては、デフォルトのツリーにもあるので注意。バージョンとかで判断。(適当)

ココからインストール。まずは cmigemo から。

$ sudo port install cmigemo +utf8

次に vim を入れる。

$ sudo port install vim +aqua +cscope +huge +kaoriya +macvim +multibyte +python +ruby

エラー吐かなければ完了。 vimgvim が使えるよ。( vim はデフォルトで入ってるけど。) 後は好みの設定を $HOME/.gvimrc に書くだけ。

以下、現状の .gvimrc っす。殆どコピペ。

"
"   .gvimrc
"
set iminsert=0 imsearch=0
set antialias
set macatsui
set guifont=Osaka-Mono:h14
set transparency=200

"   window settings.
set columns=177
set lines=53

"   syntax highlight.
hi Normal   guifg=White     guibg=Black

今後調べて整えていこう。

Posted at: 
2007/08/09 23:47:14
0 Comments
0 TrackBacks
Tags: 
Mac
MacPorts
vim
Trackback: 
http://humming.via-kitchen.com/2007/08/09/install-vim-using-privateportfile/trackback/

「SQL HACKS」買ったよ。

今日は本を買いに渋谷まで。 色々立ち読みして悩んだ結果、

の2冊を購入。

MySQL Stored Procedure Programming 」がめちゃめちゃ欲しかったものの、とりあえず値段が高いのと、それ以前に洋書だということで断念。

和訳して出してほしいなぁ。 いや、これは買ってしまうべきか?

Posted at: 
2007/08/05 22:01:21
0 Comments
0 TrackBacks
Tags: 
book
MySQL
PostgreSQL
Trackback: 
http://humming.via-kitchen.com/2007/08/05/bought-sqlhacks/trackback/

後に続け!

Voluntas さんの コチラのエントリー より。

がアップされてます! Senna - 1.0.8対応。

って事で、早速アップデート。ちゃんと入りましたよ!素敵過ぎます!

Posted at: 
2007/08/05 00:27:08
0 Comments
0 TrackBacks
Tags: 
Mac
MacPorts
MySQL
Senna
Tritonn
Trackback: 
http://humming.via-kitchen.com/2007/08/05/follow-this/trackback/

django.newformsメモ

Django -0.96から搭載された newforms 。 個人的にはコードがすっきり書けて良いと思うものの、 field とか widget を変えたい時にソースが膨れ上がってしまい、ちょっと DRY じゃ無い気がしてた。

Django -0.96の django.db.models.fields だとこうなってる。

def formfield(self, **kwargs):
    "Returns a django.newforms.Field instance for this database Field."
    defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
    defaults.update(kwargs)
    # ココがべた書き。
    return forms.CharField(**defaults)

これだと field 変えたい時にはrequiredとかの設定をもう一回自分で書かなきゃなんない。 すでに一度 model に定義してるのに。

これはさすがに無いだろ。と思って TRUNK を見るとこうなってる。

# 引数にform_classが追加されてる。
def formfield(self, form_class=forms.CharField, **kwargs):
    "Returns a django.newforms.Field instance for this database Field."
    defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
    if self.choices:
        defaults['widget'] = forms.Select(choices=self.get_choices())
    defaults.update(kwargs)
    # 動的に生成。
    return form_class(**defaults)

これだと newforms.form_for_modelformfield_callback から簡単に上書き出来るし、設定もちゃんと受け渡される。良いね。素敵。

unicodeブランチのマージとか、色々変更掛かってるみたいだし、早く0.97出てほしい。

Posted at: 
2007/08/04 22:16:32
0 Comments
0 TrackBacks
Tags: 
Django
Python
Trackback: 
http://humming.via-kitchen.com/2007/08/04/django-newforms-memo/trackback/

ManyToManyFieldをちょっとdel.icio.usっぽく

endless 氏と、

DjangoManyToManyFielddel.icio.us っぽくしたいね。」

という話になり色々と試行錯誤してみたよ。

そのまま as_text とかやると、期待した通りに動かないため、ソースと睨めっこしながら一応形になった。

なので、とりあえずメモ。

models.py はこんな感じ。

# -*- coding: utf-8 -*-

from datetime import datetime
from django.db import models


class Tag(models.Model):
    """
    ブックマークのタグ。
    """
    label = models.SlugField(_('Label'), maxlength=50, default=None)

    class Meta:
        pass

    class Admin:
        pass

    def __str__(self):
        return self.label

    def get_absolute_url(self):
        """
        インスタンスに対してのユニークなURLを返す。
        """
        return '/bookmark/tag/%s/' % self.label


class Entry(models.Model):
    """
    ブックマーク。
    """
    title       = models.CharField(_('Title'), maxlength=100, default=None)
    url         = models.URLField(_('Url'), default=None)
    description = models.TextField(_('Description'), default=None)
    created_at  = models.DateTimeField(_('Created at'), editable=False, default=datetime.now)
    updated_at  = models.DateTimeField(_('Updated at'), editable=False)
    is_active   = models.BooleanField(_('Is Active'), editable=False, default=True)
    tags        = models.ManyToManyField(Tag)

    class Meta:
        pass

    class Admin:
        list_display = ('title', 'url', 'created_at', 'updated_at', 'is_active')

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        """
        インスタンスに対してのユニークなURLを返す。
        """
        return self.url

    def save(self):
        """
        データを登録する。
        """
        self.updated_at = datetime.now()
        super(Entry, self).save()

    def delete(self):
        """
        論理削除の為のオーバーライド。
        """
        # Turn off Activation flag.
        self.is_active = False
        self.save()

で、同階層に作った forms.py がコレ。

# -*- coding: utf-8 -*-

from django.db.models.query import QuerySet
from django import newforms as forms
from tested.bookmark.models import Tag

EMPTY_VALUES = (None, '',)
ENTRY_FORMFIELDS = {}

class MultiTagInput(forms.TextInput):
    """
    ManyToMany2Charなウィジェット。
    """

    def render(self, name, value, attrs=None):
        if isinstance(value, QuerySet):
            value = ' '.join([t.label for t in value])
        return super(MultiTagInput, self).render(name, value, attrs)


class MultiTagField(forms.Field):
    """
    ManyToMany2Charなフィールド。逆もしかり。
    """

    def __init__(self, **kwargs):
        kwargs.update({
            'widget' : MultiTagInput(),
        })
        super(MultiTagField, self).__init__(**kwargs)


    def clean(self, value):
        super(MultiTagField, self).clean(value)
        values = []
        for label in value.replace('\xe3\x80\x80', ' ').split(' '):
            if len(label):
                tag, created = Tag.objects.get_or_create(label=label)
                values.append(tag.id)

        if not len(values):
            raise forms.ValidationError(_('This field is required.'))
        return values


ENTRY_FORMFIELDS['tags'] = MultiTagField

def entry_form_callback(f, **kwargs):
    """
    bookmark.Entry用のformfield_callback.
    """
    try:
        # セットされてればそれを使う。
        return ENTRY_FORMFIELDS[f.name](**kwargs)
    except:
        # 無ければデフォルト。
        return f.formfield(**kwargs)

これで views.py とかで、

f = newforms.form_for_model(Entry, formfield_callback=entry_form_callback)

とかすると、テンプレートでは input@type=text になっております。果たしてコレで合ってるのかは解りませんが。

手練の方からの突っ込みをお待ちしております!

Posted at: 
2007/08/03 02:22:55
0 Comments
0 TrackBacks
Tags: 
Django
Python
Trackback: 
http://humming.via-kitchen.com/2007/08/03/manytomanyfield-2-delicious/trackback/

Categories

Archives