ORM是对象-关系管理器,是对数据库进行操作的API接口。选择MySQL作为网站的后台数据库;执行SQL语句进行操作,并将常用的SELECT、INSERT等语句进行函数封装;在异步框架的基础上,采用aiomysql作为数据库的异步IO驱动;将数据库中表的操作,映射成一个类的操作,也就是数据库表的一行映射成一个对象(ORM)。整个ORM也是异步操作。
预备知识:Python协程和异步IO(yield from的使用)、SQL数据库操作、元类、面向对象知识、Python语法
思路
如何定义一个user类,这个类和数据库中的表User构成映射关系,二者应该关联起来,user可以操作表User
通过Field类将user类的属性映射到User表的列中,其中每一列的字段又有自己的一些属性,包括数据类型,列名,主键和默认值
python的版本是Python 3.5.2
orm.py
# -*-coding:utf-8 -*-
import asyncio, logging
import aiomysql
# 打印SQL查询语句
def log(sql, args=()):
logging.info('SQL: %s'%(sql))
# 创建一个全局的连接池,每个HTTP请求都从池中获得数据库连接
@asyncio.coroutine
def create_pool(loop, **kw):
logging.info('create database connection pool...')
# 全局变量__pool用于存储整个连接池
global __pool
__pool = yield from aiomysql.create_pool(
# **kw参数可以包含所有连接需要用到的关键字参数
# 默认本机IP
host = kw.get('host','localhost'),
user = kw['user'],
password = kw['password'],
db = kw['db'],
port = kw.get('port',3306),
charset = kw.get('charset','utf8'),
autocommit = kw.get('autocommit', True),
# 默认最大连接数为10
maxsize = kw.get('maxsize', 10),
minsize = kw.get('minisize', 1),
# 接收一个event_loop实例
loop = loop
)
# 封装SQL SELECT语句为select函数
def select(sql, args, size=None):
log(sql, args)
global __pool
# -*- yield from 将会调用一个子协程,并直接返回调用的结果
# yield from从连接池中返回一个连接
with(yield from __pool) as conn:
# DictCursor is a cursor which returns results as a dictionary
cur = yield from conn.cursor(aiomysql.DictCursor)
# 执行SQL语句
# SQL语句的占位符为?,MySQL的占位符为%s
yield from cur.execute(sql.replace('?','%s'), args or ())
# 根据指定返回的size,返回查询的结果
ifsize:
# 返回size条查询结果
rs = fetchmany(size)
else:
# 返回所有查询结果
rs = fetchall()
yield from cur.close()
logging.info('rows return: %s'%(len(rs)))
returnrs
# 封装INSERT, UPDATE, DELETE
# 语句操作参数一样,所以定义一个通用的执行函数
# 返回操作影响的行号
@asyncio.coroutine
def execute(sql, args):
log(sql, args)
global __pool
with(yield from __pool) as conn:
try:
# execute类型的SQL操作返回的结果只有行号,所以不需要用DictCursor
cur = yield from conn.cursor()
cur.execute(sql.replace('?','%s'), args)
affectedLine = cur.rowcount
yield from cur.close()
except BaseException as e:
raise
returnaffectedLine
# 根据输入的参数生成占位符列表
def create_args_string(num):
L = []
fornin range(num):
L.append('?')
# 以','为分隔符,将列表合成字符串
return(','.join(L))
# 定义Field类,负责保存(数据库)表的字段名和字段类型
class Field(object):
# 表的字段包含名字、类型、是否为表的主键和默认值
def __init__(self, name, column_type, primary_key,default):
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default=default
# 当打印(数据库)表时,输出(数据库)表的信息:类名,字段类型和名字
def __str__(self):
return('