`
xiaoyu966
  • 浏览: 254321 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

基于Torndb的简易ORM

阅读更多

============================================================================

原创作品,允许转载。转载时请务必以超链接形式标明原始出处、以及本声明。

请注明转自:http://yunjianfei.iteye.com/blog/

============================================================================ 

 

    最近在用tornado写一个基于Rest的WebService服务端,只提供后端服务,其他webserver应用通过URL,Rest的方式来访问。

 

     我们在开发web应用的时候,难免会想到ORM的一些框架,比如java ee中常用的hibernate, ibatis以及python中的SQLAlchemy之类。使用ORM会在一定程度上加快我们的开发效率。

 

      一个简易ORM框架主要实现如下几个功能就足够了:

     1.插入: 类对象映射为数据库记录

     2.查询:数据库记录映射为类对象

     3.修改、删除:可以通过自己写sql语句来搞定。

 

      python中有类,同时也有dict字典类型,如果将字典再包装为类,则显得过渡包装了,反倒很不灵活,因此,提炼一下,python的ORM框架只需要实现如下几点就足够:

     1.插入: python的dict映射为数据库记录

     2.查询:数据库记录映射为python的dict以及list等

     3.修改、删除:可以通过自己写sql语句来搞定。

    

      经过一些测试,技术选型,最终确定了使用tornadb,非常轻量级,查询数据库返回的对象直接映射为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

 

 

输出结果为:

 

<class '__main__.Row'>
dic.name: hello
dic.num: 12334

 

通过这个例子,我们可以看到,python里面的dict类型,是可以变成类似java中“对象.属性”的方式来访问的。

torndb就是通过这样的方式,查询返回的数据可以通过“.列名”来直接访问。

 

查询的时候直接返回dict或者list类型,那插入呢?如果可以像java一样,传入一个对象,通过ORM框架直接反射为sql操作,这样多方便啊~

 

还是dict,如果我们插入的时候,直接将插入的数据格式保存为dict,通过这个dict生成insert语句就可以了,经过查阅各种资料,我提炼出来了如下方法:(使用的时候直接将该方法放入torndb.py中即可)

    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封装,比如:

有个host表,里面有hostname,ip两个字段,则我们可以用如下几行代码,就可以插入到数据库:

    host = {}
    host['hostname'] = 'test1'
    host['ip'] = '10.22.10.90'
    ret = db.insert_by_dict("Host", host)

 

是不是很方便呢?:)附件里是我修改过后,完整的torndb源码。欢迎大家多多下载使用。

 

 外带一个小例子,完整版请参照我在github上发布的一个webservice框架:https://github.com/yunfeiflying/tornado-rest-web-service-framwork/

 

#!/usr/bin/env python2.7
#
# -*- coding:utf-8 -*-
#
#   Author  :   YunJianFei
#   E-mail  :   yunjianfei@126.com
#   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

 

 

 

 

1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics