Torndbベースの簡易ORM


===============================================================================================================================
オリジナル作品は、転載を許可します。転載時は必ずハイパーリンクで元の出典と本声明を明示してください。
自己転記を明記してくださいhttp://yunjianfei.iteye.com/blog/
=============================================================================================================================== 
 
    最近tonadoでReserviceサービスを提供しています。他のwebserverアプリケーションはURL、Resertを通じてアクセスします。
 
     私たちはwebアプリケーションを開発する時、java eeでよく使われているhibernateやibatis、pythonのSQLAlchemyなどのORMの枠組みを考えることができます。ORMを使うと、ある程度の開発効率が上がります。
 
      簡単なORMフレームワークは主に以下のような機能を実現すれば十分です。
     1.挿入:クラスオブジェクトをデータベースレコードにマッピングする
     2.クエリー:データベースレコードをクラスオブジェクトにマッピングする
     3.修正、削除:自分でsql文を書くことで解決できます。
 
      pythonには種類がありますが、dict辞書の種類もあります。もし辞書をクラスに包装すれば、移行包装に見えます。逆にフレキシブルではないので、精錬してください。pythonのORMの枠組みは以下のような点だけで十分です。
     1.挿入:pythonのdictをデータベースレコードにマッピングする
     2.クエリー:データベースレコードはpythonのdictおよびlistなどにマッピングされます。
     3.修正、削除:自分でsql文を書くことで解決できます。
    
      いくつかのテストを経て、技術選択型は最終的にtonadbを使用して、非常に軽量で、照会データベースから返されたオブジェクトは直接pythonのデータタイプdictまたはlistのようにマッピングされます。javaの「オブジェクト・属性」と同様にデータにアクセスすることができます。これは本当に気持ちいいです。まず、例を見てください。
 
 
import types
import time

class Row(dict):
    """A dict that allows for object-like property access syntax."""
    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

dic = Row()
dic.name = 'hello'
dic.num = '12334'
print type(dic)
print "dic.name: " + dic.name
print "dic.num: " + dic.num
 
 
出力結果は:
 
〈クラス〉_メーン.Row'
dic.name:hello
dic.num:12334
 
この例を通して、pythonの中のdictタイプは、javaの「オブジェクト・属性」のようにアクセスできるようになります。
tondbはこのようにして、検索したデータは「.列名」で直接アクセスできます。
 
検索する時は直接dictまたはlistタイプに戻りますが、挿入しますか?javaのように、一つの対象に入ることができれば、ORMフレームを通して直接にsqlに反射して操作するのが便利です。
 
それともdictですか?挿入する時、直接に挿入したデータフォーマットをdictとして保存して、このdictを通じてinsert文を生成すればいいです。各種の資料を調べて、次のような方法を抽出しました。
    def insert_by_dict(self, tablename, rowdict, replace=False):
        cursor = self._cursor()
        cursor.execute("describe %s" % tablename)
        allowed_keys = set(row[0] for row in cursor.fetchall())
        keys = allowed_keys.intersection(rowdict)

        if len(rowdict) > len(keys):
            unknown_keys = set(rowdict) - allowed_keys
            logging.error("skipping keys: %s", ", ".join(unknown_keys))

        columns = ", ".join(keys)
        values_template = ", ".join(["%s"] * len(keys))

        if replace:
            sql = "REPLACE INTO %s (%s) VALUES (%s)" % (
                tablename, columns, values_template)
        else:
            sql = "INSERT INTO %s (%s) VALUES (%s)" % (
                tablename, columns, values_template)

        values = tuple(rowdict[key] for key in keys)
        try:
            cursor.execute(sql, values)
            #self._execute(cursor, sql, values, None)
            return cursor.lastrowid
        finally:
            cursor.close()
 
このように挿入する時、私達はもうくどいsql文を書かなくてもいいです。私達が挿入する対象をdictパッケージを使うだけです。
ホームリストがあります。中にhostname、ipの二つのフィールドがあります。次のコードを使って、データベースに挿入できます。
    host = {}
    host['hostname'] = 'test1'
    host['ip'] = '10.22.10.90'
    ret = db.insert_by_dict("Host", host)
 
便利ですか?添付ファイルは私が修正した後、完全なtondbソースです。ダウンロードして使ってください。
 
 バンドの一例として、完全版はgithubで発表したwebserviceフレームを参照してください。https://github.com/yunfeiflying/tornado-rest-web-service-framwork/
 
#!/usr/bin/env python2.7
#
# -*- coding:utf-8 -*-
#
#   Author  :   YunJianFei
#   E-mail  :   [email protected]
#   Date    :   2014/02/25
#   Desc    :   Test db
#

""" Data Access Object
    This file impelements DBI for the table 'Host'

The Host table's create sql is : 

CREATE TABLE IF NOT EXISTS `test`.`Host` (
  `host_id` INT NOT NULL AUTO_INCREMENT,
  `host_type` INT NULL,
  `hostname` VARCHAR(45) NULL,
  `ip` VARCHAR(45) NULL,
  `create_time` VARCHAR(45) NULL,
  `cpu_count` INT NULL,
  `cpu_pcount` INT NULL,
  `memory` INT NULL,
  `os` VARCHAR(200) NULL,
  `comment` VARCHAR(200) NULL,
  PRIMARY KEY (`host_id`))
ENGINE = InnoDB;

"""

from util.dbconst import TableName, TableFields, TableSelectSql
import logging

class HostDao:
    def __init__(self, db):
        mysql_host = "192.168.10.11:3306"
        db_name = "test"
        db_user = "root"
        db_pass = ""

        self.db = torndb.Connection(
            host=mysql_host, database=db_name,
            user=db_user, password=db_pass
        )

    def insert_by_dict(self, host, replace=False):
        try:
            id = self.db.insert_by_dict("Host", host, replace)
            return id
        except Exception, ex:
            logging.error("Insert host failed! Exception: %s   Host: %s", str(ex), str(host))
            return None

    def if_exist(self, hostname, ip):
        ret = self.get_by_hostname(hostname)
        if ret != None:
            return True

        ret = self.get_by_ip(ip)
        if ret != None:
            return True

        return False

    def get_by_ip(self, ip):
        sql = TableSelectSql.HOST + " where ip='" + str(ip)+"'"
        return self.db.get(sql)

    def get_all(self):
        sql = TableSelectSql.HOST
        return self.db.query(sql)

    def get_by_hostname(self, hostname):
        sql = TableSelectSql.HOST + " where hostname='" + str(hostname)+"'"
        return self.db.get(sql)

    def get_by_id(self, host_id):
        sql = TableSelectSql.HOST + " where host_id=%s" % str(host_id)
        return self.db.get(sql)

    def get_id_by_hostname(self, hostname):
        sql = TableSelectSql.HOST + " where hostname='" + str(hostname)+"'"
        ret = self.db.get(sql)
        if ret != None:
            return ret.host_id
        return None

    def update_worker_num_by_hostname(self, hostname, worker_num):
        try:
            sql = "UPDATE Host SET worker_num=%s WHERE hostname='%s'" % (worker_num, str(hostname))
            ret = self.db.execute(sql)
            return ret
        except Exception, ex:
            logging.error("Update Host failed! Exception: %s   hostname: %s , worker_num: %s", str(ex), str(hostname), worker_num)
            return None

    def update_worker_num_by_id(self, host_id, worker_num):
        try:
            sql = "UPDATE Host SET worker_num=%s WHERE host_id=%s" % (worker_num, host_id)
            ret = self.db.execute(sql)
            return ret
        except Exception, ex:
            logging.error("Update Host failed! Exception: %s   host_id: %s , worker_num: %s", str(ex), host_id, worker_num)
            return None

    def del_by_hostname(self, hostname):
        try:
            sql = "DELETE FROM Host WHERE hostname='" + str(hostname) + "'"
            ret = self.db.execute(sql)
            return ret
        except Exception, ex:
            logging.error("Delete host failed! Exception: %s   hostname: %s", str(ex), str(hostname))
            return None

    def del_by_id(self, host_id):
        try:
            sql = "DELETE FROM Host WHERE host_id=" + str(host_id)
            ret = self.db.execute(sql)
            return ret
        except Exception, ex:
            logging.error("Delete host failed! Exception: %s   host_id: %s", str(ex), host_id)
            return None