KvsModel: KVS(TokyoTyrantなど)をモデルっぽく使う
Django
2011-06-12 03:17 (15 years ago)

# -*- coding: utf-8 -*-
"""
KVS(TokyoTyrantなど)をモデルっぽく使う
今回は Django のキャッシュを扱う
モデルといってもリレーションや検索などを提供するわけではなく
フィールド定義がmodels.Modelみたいにできる。
(要は、中でもってるディクショナリ(storage)のキー名を変数名から自動的につけてくれる)
class Soldier(KvsModel):
hp = KvsModel.Field(default=0)
mp = KvsModel.Field(default=0)
cain = Soldier('Cain')
cain.hp = 100
cain.mp = 50
cain.save()
abel = Soldier('Abel')
abel.hp = 50
abel.mp = 100
abel.save()
cain = Soldier('Cain')
cain.hp -= 80
cain.save()
abel = Soldier('Abel')
abel.mp -= 20
abel.save()
cain = Soldier('Cain')
cain.hp = min(cain.hp + 50, 100)
cain.save()
cain = Soldier('Cain')
cain.hp
Out: 70
cain.dump()
Out: "[Soldier] dump: kvs_key=Soldier::Cain, storage={'hp': 70, 'mp': 50}"
abel.dump()
Out: "[Soldier] dump: kvs_key=Soldier::Abel, storage={'hp': 50, 'mp': 80}"
"""
import msgpack #pip install msgpack-python
from django.core.cache import cache as kvs_backend
class KvsModel(object):
"""
TokyoTyrantなどをディクショナリとして使う基底クラス
継承して使ってください
"""
packer = msgpack.Packer()
def __new__(cls, *args, **kwargs):
for k, v in vars(cls).iteritems():
if isinstance(v, KvsModel.Field):
v.set_field_name(k)
return object.__new__(cls)
def __init__(self, key_object):
"""
@param key_object djangoのモデルインスタンスなど。
オーバーライドして、superの__init__を呼ぶ必要が無い時は
そのまま self.after_init(key_part) する
"""
self.key_object = key_object
key_part = getattr(key_object, 'pk', str(key_object))
self.after_init(key_part)
def after_init(self, key_part):
"""
初期化処理の後半
@param (str)key_part キー生成の元となるユニークな文字列
"""
self.kvs_key = '%s::%s' % (self.__class__.__name__, key_part)
bulk_storage = kvs_backend.get(self.kvs_key, None)
if bulk_storage:
self.storage = msgpack.unpackb(bulk_storage)
else:
self.storage = {}
def get(self, k, default=None):
return self.storage.get(k,default)
def set(self, k, value):
self.storage[k] = value
def save(self):
"""
storageを保存
"""
kvs_backend.set(self.kvs_key, self.packer.pack(self.storage))
def delete(self):
"""
storageを削除
"""
kvs_backend.delete(self.kvs_key)
self.storage = {}
def dump(self):
return "[%s] dump: kvs_key=%s, storage=%r" % (self.__class__.__name__, self.kvs_key, self.storage)
class Field(object):
"""
KvsModel に使えるフィールド
score = KvsModel.Field(default=0) みたいに使う。
"""
def __init__(self, key_name=None, default=None):
self._key_name = key_name
self.default = default
def __get__(self, inst, type=None):
assert isinstance(inst, KvsModel), '%s use only KvsModel class.' % self.__class__.__name__
return inst.get(self.key_name, self.default)
def __set__(self, inst, value):
assert isinstance(inst, KvsModel), '%s use only KvsModel class.' % self.__class__.__name__
inst.set(self.key_name, value)
def set_field_name(self, field_name):
#TokyoTyrantStorage.__new__ から呼ばれる
self.field_name = field_name
@property
def key_name(self):
return self._key_name or self.field_name
評価をお願いします (会員登録・ログイン不要)
まだ評価がありません
著者は、アプリケーション開発会社 Cyberneura を運営しています。
開発相談をお待ちしています。
開発相談をお待ちしています。