<code>#!/usr/bin/env python3</code>
<code># -*- coding: utf-8 -*-</code>
<code>__author__ </code><code>=</code> <code>'Michael Liao'</code>
<code>import</code> <code>asyncio, logging</code>
<code>import</code> <code>aiomysql</code>
<code>def</code> <code>log(sql, args</code><code>=</code><code>()):</code>
<code> </code><code>logging.info(</code><code>'SQL: %s'</code> <code>%</code> <code>sql)</code>
<code>#代码分为三部分,第一部分是aiomysql模块的应用</code>
<code>async </code><code>def</code> <code>create_pool(loop, </code><code>*</code><code>*</code><code>kw):</code>
<code> </code><code>logging.info(</code><code>'create database connection pool...'</code><code>)</code>
<code> </code><code>global</code> <code>__pool</code>
<code> </code><code>__pool </code><code>=</code> <code>await aiomysql.create_pool(</code>
<code> </code><code>host</code><code>=</code><code>kw.get(</code><code>'host'</code><code>, </code><code>'localhost'</code><code>),</code>
<code> </code><code>port</code><code>=</code><code>kw.get(</code><code>'port'</code><code>, </code><code>3306</code><code>),</code>
<code> </code><code>user</code><code>=</code><code>kw[</code><code>'user'</code><code>],</code>
<code> </code><code>password</code><code>=</code><code>kw[</code><code>'password'</code><code>],</code>
<code> </code><code>db</code><code>=</code><code>kw[</code><code>'db'</code><code>],</code>
<code> </code><code>charset</code><code>=</code><code>kw.get(</code><code>'charset'</code><code>, </code><code>'utf8'</code><code>),</code>
<code> </code><code>autocommit</code><code>=</code><code>kw.get(</code><code>'autocommit'</code><code>, </code><code>True</code><code>),</code>
<code> </code><code>maxsize</code><code>=</code><code>kw.get(</code><code>'maxsize'</code><code>, </code><code>10</code><code>),</code>
<code> </code><code>minsize</code><code>=</code><code>kw.get(</code><code>'minsize'</code><code>, </code><code>1</code><code>),</code>
<code> </code><code>loop</code><code>=</code><code>loop</code>
<code> </code><code>)</code>
<code>async </code><code>def</code> <code>select(sql, args, size</code><code>=</code><code>None</code><code>):</code>
<code> </code><code>log(sql, args)</code>
<code> </code><code>async with __pool.get() as conn:</code>
<code> </code><code>async with conn.cursor(aiomysql.DictCursor) as cur:</code>
<code> </code><code>await cur.execute(sql.replace(</code><code>'?'</code><code>, </code><code>'%s'</code><code>), args </code><code>or</code> <code>())</code>
<code> </code><code>if</code> <code>size:</code>
<code> </code><code>rs </code><code>=</code> <code>await cur.fetchmany(size)</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>rs </code><code>=</code> <code>await cur.fetchall()</code>
<code> </code><code>logging.info(</code><code>'rows returned: %s'</code> <code>%</code> <code>len</code><code>(rs))</code>
<code> </code><code>return</code> <code>rs</code>
<code>async </code><code>def</code> <code>execute(sql, args, autocommit</code><code>=</code><code>True</code><code>):</code>
<code> </code><code>log(sql)</code>
<code> </code><code>if</code> <code>not</code> <code>autocommit:</code>
<code> </code><code>await conn.begin()</code>
<code> </code><code>try</code><code>:</code>
<code> </code><code>async with conn.cursor(aiomysql.DictCursor) as cur:</code>
<code> </code><code>await cur.execute(sql.replace(</code><code>'?'</code><code>, </code><code>'%s'</code><code>), args)</code>
<code> </code><code>affected </code><code>=</code> <code>cur.rowcount</code>
<code> </code><code>if</code> <code>not</code> <code>autocommit:</code>
<code> </code><code>await conn.commit()</code>
<code> </code><code>except</code> <code>BaseException as e:</code>
<code> </code><code>await conn.rollback()</code>
<code> </code><code>raise</code>
<code> </code><code>return</code> <code>affected</code>
<code>def</code> <code>create_args_string(num):</code>
<code> </code><code>L </code><code>=</code> <code>[]</code>
<code> </code><code>for</code> <code>n </code><code>in</code> <code>range</code><code>(num):</code>
<code> </code><code>L.append(</code><code>'?'</code><code>)</code>
<code> </code><code>return</code> <code>', '</code><code>.join(L)</code>
<code>#代码分为三部分,第二部分是orm的实际应用</code>
<code>class</code> <code>Field(</code><code>object</code><code>):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, name, column_type, primary_key, default):</code>
<code> </code><code>self</code><code>.name </code><code>=</code> <code>name</code>
<code> </code><code>self</code><code>.column_type </code><code>=</code> <code>column_type</code>
<code> </code><code>self</code><code>.primary_key </code><code>=</code> <code>primary_key</code>
<code> </code><code>self</code><code>.default </code><code>=</code> <code>default</code>
<code> </code><code>def</code> <code>__str__(</code><code>self</code><code>):</code>
<code> </code><code>return</code> <code>'<%s, %s:%s>'</code> <code>%</code> <code>(</code><code>self</code><code>.__class__.__name__, </code><code>self</code><code>.column_type, </code><code>self</code><code>.name)</code>
<code>class</code> <code>StringField(Field):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, name</code><code>=</code><code>None</code><code>, primary_key</code><code>=</code><code>False</code><code>, default</code><code>=</code><code>None</code><code>, ddl</code><code>=</code><code>'varchar(100)'</code><code>):</code>
<code> </code><code>super</code><code>().__init__(name, ddl, primary_key, default)</code>
<code>class</code> <code>BooleanField(Field):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, name</code><code>=</code><code>None</code><code>, default</code><code>=</code><code>False</code><code>):</code>
<code> </code><code>super</code><code>().__init__(name, </code><code>'boolean'</code><code>, </code><code>False</code><code>, default)</code>
<code>class</code> <code>IntegerField(Field):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, name</code><code>=</code><code>None</code><code>, primary_key</code><code>=</code><code>False</code><code>, default</code><code>=</code><code>0</code><code>):</code>
<code> </code><code>super</code><code>().__init__(name, </code><code>'bigint'</code><code>, primary_key, default)</code>
<code>class</code> <code>FloatField(Field):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, name</code><code>=</code><code>None</code><code>, primary_key</code><code>=</code><code>False</code><code>, default</code><code>=</code><code>0.0</code><code>):</code>
<code> </code><code>super</code><code>().__init__(name, </code><code>'real'</code><code>, primary_key, default)</code>
<code>class</code> <code>TextField(Field):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, name</code><code>=</code><code>None</code><code>, default</code><code>=</code><code>None</code><code>):</code>
<code> </code><code>super</code><code>().__init__(name, </code><code>'text'</code><code>, </code><code>False</code><code>, default)</code>
<code>class</code> <code>ModelMetaclass(</code><code>type</code><code>):</code>
<code> </code><code>def</code> <code>__new__(</code><code>cls</code><code>, name, bases, attrs):</code>
<code> </code><code>if</code> <code>name</code><code>=</code><code>=</code><code>'Model'</code><code>:</code>
<code> </code><code>return</code> <code>type</code><code>.__new__(</code><code>cls</code><code>, name, bases, attrs)</code>
<code> </code><code>tableName </code><code>=</code> <code>attrs.get(</code><code>'__table__'</code><code>, </code><code>None</code><code>) </code><code>or</code> <code>name</code>
<code> </code><code>logging.info(</code><code>'found model: %s (table: %s)'</code> <code>%</code> <code>(name, tableName))</code>
<code> </code><code>mappings </code><code>=</code> <code>dict</code><code>()</code>
<code> </code><code>fields </code><code>=</code> <code>[]</code>
<code> </code><code>primaryKey </code><code>=</code> <code>None</code>
<code> </code><code>for</code> <code>k, v </code><code>in</code> <code>attrs.items():</code>
<code> </code><code>if</code> <code>isinstance</code><code>(v, Field):</code>
<code> </code><code>logging.info(</code><code>' found mapping: %s ==> %s'</code> <code>%</code> <code>(k, v))</code>
<code> </code><code>mappings[k] </code><code>=</code> <code>v</code>
<code> </code><code>if</code> <code>v.primary_key:</code>
<code> </code><code># 找到主键:</code>
<code> </code><code>if</code> <code>primaryKey:</code>
<code> </code><code>raise</code> <code>BaseException(</code><code>'Duplicate primary key for field: %s'</code> <code>%</code> <code>k)</code>
<code> </code><code>primaryKey </code><code>=</code> <code>k</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>fields.append(k)</code>
<code> </code><code>if</code> <code>not</code> <code>primaryKey:</code>
<code> </code><code>raise</code> <code>BaseException(</code><code>'Primary key not found.'</code><code>)</code>
<code> </code><code>for</code> <code>k </code><code>in</code> <code>mappings.keys():</code>
<code> </code><code>attrs.pop(k)</code>
<code> </code><code>escaped_fields </code><code>=</code> <code>list</code><code>(</code><code>map</code><code>(</code><code>lambda</code> <code>f: </code><code>'`%s`'</code> <code>%</code> <code>f, fields))</code>
<code> </code><code>attrs[</code><code>'__mappings__'</code><code>] </code><code>=</code> <code>mappings </code><code># 保存属性和列的映射关系</code>
<code> </code><code>attrs[</code><code>'__table__'</code><code>] </code><code>=</code> <code>tableName</code>
<code> </code><code>attrs[</code><code>'__primary_key__'</code><code>] </code><code>=</code> <code>primaryKey </code><code># 主键属性名</code>
<code> </code><code>attrs[</code><code>'__fields__'</code><code>] </code><code>=</code> <code>fields </code><code># 除主键外的属性名</code>
<code> </code><code>attrs[</code><code>'__select__'</code><code>] </code><code>=</code> <code>'select `%s`, %s from `%s`'</code> <code>%</code> <code>(primaryKey, </code><code>', '</code><code>.join(escaped_fields), tableName)</code>
<code> </code><code>attrs[</code><code>'__insert__'</code><code>] </code><code>=</code> <code>'insert into `%s` (%s, `%s`) values (%s)'</code> <code>%</code> <code>(tableName, </code><code>', '</code><code>.join(escaped_fields), primaryKey, create_args_string(</code><code>len</code><code>(escaped_fields) </code><code>+</code> <code>1</code><code>))</code>
<code> </code><code>attrs[</code><code>'__update__'</code><code>] </code><code>=</code> <code>'update `%s` set %s where `%s`=?'</code> <code>%</code> <code>(tableName, </code><code>', '</code><code>.join(</code><code>map</code><code>(</code><code>lambda</code> <code>f: </code><code>'`%s`=?'</code> <code>%</code> <code>(mappings.get(f).name </code><code>or</code> <code>f), fields)), primaryKey)</code>
<code> </code><code>attrs[</code><code>'__delete__'</code><code>] </code><code>=</code> <code>'delete from `%s` where `%s`=?'</code> <code>%</code> <code>(tableName, primaryKey)</code>
<code> </code><code>return</code> <code>type</code><code>.__new__(</code><code>cls</code><code>, name, bases, attrs)</code>
<code>#代码分为三部分,第三部分是调用方法</code>
<code>class</code> <code>Model(</code><code>dict</code><code>, metaclass</code><code>=</code><code>ModelMetaclass):</code>
<code> </code><code>def</code> <code>__init__(</code><code>self</code><code>, </code><code>*</code><code>*</code><code>kw):</code>
<code> </code><code>super</code><code>(Model, </code><code>self</code><code>).__init__(</code><code>*</code><code>*</code><code>kw)</code>
<code> </code><code>def</code> <code>__getattr__(</code><code>self</code><code>, key):</code>
<code> </code><code>return</code> <code>self</code><code>[key]</code>
<code> </code><code>except</code> <code>KeyError:</code>
<code> </code><code>raise</code> <code>AttributeError(r</code><code>"'Model' object has no attribute '%s'"</code> <code>%</code> <code>key)</code>
<code> </code><code>def</code> <code>__setattr__(</code><code>self</code><code>, key, value):</code>
<code> </code><code>self</code><code>[key] </code><code>=</code> <code>value</code>
<code> </code><code>def</code> <code>getValue(</code><code>self</code><code>, key):</code>
<code> </code><code>return</code> <code>getattr</code><code>(</code><code>self</code><code>, key, </code><code>None</code><code>)</code>
<code> </code><code>def</code> <code>getValueOrDefault(</code><code>self</code><code>, key):</code>
<code> </code><code>value </code><code>=</code> <code>getattr</code><code>(</code><code>self</code><code>, key, </code><code>None</code><code>)</code>
<code> </code><code>if</code> <code>value </code><code>is</code> <code>None</code><code>:</code>
<code> </code><code>field </code><code>=</code> <code>self</code><code>.__mappings__[key]</code>
<code> </code><code>if</code> <code>field.default </code><code>is</code> <code>not</code> <code>None</code><code>:</code>
<code> </code><code>value </code><code>=</code> <code>field.default() </code><code>if</code> <code>callable</code><code>(field.default) </code><code>else</code> <code>field.default</code>
<code> </code><code>logging.debug(</code><code>'using default value for %s: %s'</code> <code>%</code> <code>(key, </code><code>str</code><code>(value)))</code>
<code> </code><code>setattr</code><code>(</code><code>self</code><code>, key, value)</code>
<code> </code><code>return</code> <code>value</code>
<code> </code><code>@</code><code>classmethod</code>
<code> </code><code>async </code><code>def</code> <code>findAll(</code><code>cls</code><code>, where</code><code>=</code><code>None</code><code>, args</code><code>=</code><code>None</code><code>, </code><code>*</code><code>*</code><code>kw):</code>
<code> </code><code>' find objects by where clause. '</code>
<code> </code><code>sql </code><code>=</code> <code>[</code><code>cls</code><code>.__select__]</code>
<code> </code><code>if</code> <code>where:</code>
<code> </code><code>sql.append(</code><code>'where'</code><code>)</code>
<code> </code><code>sql.append(where)</code>
<code> </code><code>if</code> <code>args </code><code>is</code> <code>None</code><code>:</code>
<code> </code><code>args </code><code>=</code> <code>[]</code>
<code> </code><code>orderBy </code><code>=</code> <code>kw.get(</code><code>'orderBy'</code><code>, </code><code>None</code><code>)</code>
<code> </code><code>if</code> <code>orderBy:</code>
<code> </code><code>sql.append(</code><code>'order by'</code><code>)</code>
<code> </code><code>sql.append(orderBy)</code>
<code> </code><code>limit </code><code>=</code> <code>kw.get(</code><code>'limit'</code><code>, </code><code>None</code><code>)</code>
<code> </code><code>if</code> <code>limit </code><code>is</code> <code>not</code> <code>None</code><code>:</code>
<code> </code><code>sql.append(</code><code>'limit'</code><code>)</code>
<code> </code><code>if</code> <code>isinstance</code><code>(limit, </code><code>int</code><code>):</code>
<code> </code><code>sql.append(</code><code>'?'</code><code>)</code>
<code> </code><code>args.append(limit)</code>
<code> </code><code>elif</code> <code>isinstance</code><code>(limit, </code><code>tuple</code><code>) </code><code>and</code> <code>len</code><code>(limit) </code><code>=</code><code>=</code> <code>2</code><code>:</code>
<code> </code><code>sql.append(</code><code>'?, ?'</code><code>)</code>
<code> </code><code>args.extend(limit)</code>
<code> </code><code>raise</code> <code>ValueError(</code><code>'Invalid limit value: %s'</code> <code>%</code> <code>str</code><code>(limit))</code>
<code> </code><code>rs </code><code>=</code> <code>await select(</code><code>' '</code><code>.join(sql), args)</code>
<code> </code><code>return</code> <code>[</code><code>cls</code><code>(</code><code>*</code><code>*</code><code>r) </code><code>for</code> <code>r </code><code>in</code> <code>rs]</code>
<code> </code><code>async </code><code>def</code> <code>findNumber(</code><code>cls</code><code>, selectField, where</code><code>=</code><code>None</code><code>, args</code><code>=</code><code>None</code><code>):</code>
<code> </code><code>' find number by select and where. '</code>
<code> </code><code>sql </code><code>=</code> <code>[</code><code>'select %s _num_ from `%s`'</code> <code>%</code> <code>(selectField, </code><code>cls</code><code>.__table__)]</code>
<code> </code><code>rs </code><code>=</code> <code>await select(</code><code>' '</code><code>.join(sql), args, </code><code>1</code><code>)</code>
<code> </code><code>if</code> <code>len</code><code>(rs) </code><code>=</code><code>=</code> <code>0</code><code>:</code>
<code> </code><code>return</code> <code>None</code>
<code> </code><code>return</code> <code>rs[</code><code>0</code><code>][</code><code>'_num_'</code><code>]</code>
<code> </code><code>async </code><code>def</code> <code>find(</code><code>cls</code><code>, pk):</code>
<code> </code><code>' find object by primary key. '</code>
<code> </code><code>rs </code><code>=</code> <code>await select(</code><code>'%s where `%s`=?'</code> <code>%</code> <code>(</code><code>cls</code><code>.__select__, </code><code>cls</code><code>.__primary_key__), [pk], </code><code>1</code><code>)</code>
<code> </code><code>return</code> <code>cls</code><code>(</code><code>*</code><code>*</code><code>rs[</code><code>0</code><code>])</code>
<code> </code><code>async </code><code>def</code> <code>save(</code><code>self</code><code>):</code>
<code> </code><code>args </code><code>=</code> <code>list</code><code>(</code><code>map</code><code>(</code><code>self</code><code>.getValueOrDefault, </code><code>self</code><code>.__fields__))</code>
<code> </code><code>args.append(</code><code>self</code><code>.getValueOrDefault(</code><code>self</code><code>.__primary_key__))</code>
<code> </code><code>rows </code><code>=</code> <code>await execute(</code><code>self</code><code>.__insert__, args)</code>
<code> </code><code>if</code> <code>rows !</code><code>=</code> <code>1</code><code>:</code>
<code> </code><code>logging.warn(</code><code>'failed to insert record: affected rows: %s'</code> <code>%</code> <code>rows)</code>
<code> </code><code>async </code><code>def</code> <code>update(</code><code>self</code><code>):</code>
<code> </code><code>args </code><code>=</code> <code>list</code><code>(</code><code>map</code><code>(</code><code>self</code><code>.getValue, </code><code>self</code><code>.__fields__))</code>
<code> </code><code>args.append(</code><code>self</code><code>.getValue(</code><code>self</code><code>.__primary_key__))</code>
<code> </code><code>rows </code><code>=</code> <code>await execute(</code><code>self</code><code>.__update__, args)</code>
<code> </code><code>logging.warn(</code><code>'failed to update by primary key: affected rows: %s'</code> <code>%</code> <code>rows)</code>
<code> </code><code>async </code><code>def</code> <code>remove(</code><code>self</code><code>):</code>
<code> </code><code>args </code><code>=</code> <code>[</code><code>self</code><code>.getValue(</code><code>self</code><code>.__primary_key__)]</code>
<code> </code><code>rows </code><code>=</code> <code>await execute(</code><code>self</code><code>.__delete__, args)</code>
<code> </code><code>logging.warn(</code><code>'failed to remove by primary key: affected rows: %s'</code> <code>%</code> <code>rows)</code>
本文转自 liqius 51CTO博客,原文链接:http://blog.51cto.com/szgb17/1941168,如需转载请自行联系原作者