Python MySQL ORM QuickORM hacking

來源:互聯網
上載者:User

標籤:

# coding: utf-8##                 Python MySQL ORM QuickORM hacking# 說明:#     以前僅僅是知道有ORM的存在,但是對ORM這個東西內部工作原理不是很清楚,# 這次正好需要用到,於是解讀一個相對來說很簡單的Python2 ORM的例子。## 參考源碼:#     A simple ORM provides elegant API for Python-MySQL operation#         https://github.com/2shou/QuickORM##                                  2016-10-15 深圳 南山平山村 曾劍鋒import MySQLdb## 作為和資料庫中欄位對應的域,同樣也作為類屬性存在# class Field(object):    passclass Expr(object):    # 合成where查詢部分    def __init__(self, model, kwargs):        self.model = model        # How to deal with a non-dict parameter?        # 提取索引值對的value部分        self.params = kwargs.values()        # 提取索引值對的key部分,併合成替代字串        equations = [key + ‘ = %s‘ for key in kwargs.keys()]        self.where_expr = ‘where ‘ + ‘ and ‘.join(equations) if len(equations) > 0 else ‘‘    def update(self, **kwargs):        _keys = []        _params = []        # 篩選資料        for key, val in kwargs.iteritems():            if val is None or key not in self.model.fields:                continue            _keys.append(key)            _params.append(val)        # 和__init__中的索引值對的values資料聯合        _params.extend(self.params)        # 合成查詢語句        sql = ‘update %s set %s %s;‘ % (            self.model.db_table, ‘, ‘.join([key + ‘ = %s‘ for key in _keys]), self.where_expr)        return Database.execute(sql, _params)    def limit(self, rows, offset=None):        # 合成limit資料,這裡就是合成想從那一行開始取資料,取多少資料        self.where_expr += ‘ limit %s%s‘ % (            ‘%s, ‘ % offset if offset is not None else ‘‘, rows)        return self    def select(self):        # 合成查詢語句,需要查詢的欄位,表明,條件        sql = ‘select %s from %s %s;‘ % (‘, ‘.join(self.model.fields.keys()), self.model.db_table, self.where_expr)        # 取出所有的資料,這裡使用了yield,使得select可以被for in文法再次迭代從而擷取到值        for row in Database.execute(sql, self.params).fetchall():            # 擷取傳入的模板類型,這樣就不用知道是什麼類運行了select            inst = self.model()            # 擷取一條資訊中的值            for idx, f in enumerate(row):                setattr(inst, self.model.fields.keys()[idx], f)            yield inst    # 返回查詢的資料統計總數    def count(self):        sql = ‘select count(*) from %s %s;‘ % (self.model.db_table, self.where_expr)        (row_cnt, ) = Database.execute(sql, self.params).fetchone()        return row_cntclass MetaModel(type):    db_table = None    fields = {}    def __init__(cls, name, bases, attrs):        super(MetaModel, cls).__init__(name, bases, attrs)        fields = {}        # 從類所有的屬性中提取出類屬性,和資料庫中的欄位對應,這裡更多的給Expr類使用。        for key, val in cls.__dict__.iteritems():            if isinstance(val, Field):                fields[key] = val        cls.fields = fields        cls.attrs = attrsclass Model(object):    # 採用MetaModel來構建Model類    __metaclass__ = MetaModel    # 動態產生對應的sql語句,並執行對應的語句,要注意這裡是self.__dict__擷取的執行個體屬性。    def save(self):        insert = ‘insert ignore into %s(%s) values (%s);‘ % (            self.db_table, ‘, ‘.join(self.__dict__.keys()), ‘, ‘.join([‘%s‘] * len(self.__dict__)))        return Database.execute(insert, self.__dict__.values())    # 使用where來查詢    @classmethod    def where(cls, **kwargs):        return Expr(cls, kwargs)class Database(object):    autocommit = True    conn = None    db_config = {}    # 通過db_config字典資料設定串連資料庫的值    @classmethod    def connect(cls, **db_config):        cls.conn = MySQLdb.connect(host=db_config.get(‘host‘, ‘localhost‘), port=int(db_config.get(‘port‘, 3306)),                                   user=db_config.get(‘user‘, ‘root‘), passwd=db_config.get(‘password‘, ‘‘),                                   db=db_config.get(‘database‘, ‘test‘), charset=db_config.get(‘charset‘, ‘utf8‘))        cls.conn.autocommit(cls.autocommit)        cls.db_config.update(db_config)    # 這裡是串連資料庫,裡面有一些策略,譬如:    #     1. 如果沒有串連資料庫,那麼就串連資料庫;    #     2. 如果串連了資料庫,那麼測試是否可ping通再返回串連;    #     3. 如果ping不通,那麼重新串連,再返回。    @classmethod    def get_conn(cls):        if not cls.conn or not cls.conn.open:            cls.connect(**cls.db_config)        try:            cls.conn.ping()        except MySQLdb.OperationalError:            cls.connect(**cls.db_config)        return cls.conn    # 這裡是直接執行sql語句,返回的是執行後的cursor    @classmethod    def execute(cls, *args):        cursor = cls.get_conn().cursor()        cursor.execute(*args)        return cursor    # 對象被記憶體回收機回收的時候調用    def __del__(self):        if self.conn and self.conn.open:            self.conn.close()# 執行原始sql語句def execute_raw_sql(sql, params=None):    return Database.execute(sql, params) if params else Database.execute(sql)

 

Python MySQL ORM QuickORM hacking

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.