Python3学到现在,进入了实战项目阶段:搭建个人博客。
day3的内容,我消化了好几天,今天大致清晰了,完成了编码和粗略测试,这里做个记录。
1. 难点一:理解ORM是关键
ORM:object relationship model 对象关系映射
我的理解:在一个项目里面,需要对数据库进行大量的操作(一个项目,说白了,就是界面+对数据库的增删查改),在不同的地方重复操作数据库,即多次重复与数据库的交互,这样,不仅造成代码冗余,而且导致后期的修改维护不方便。面对这种情况,orm的概念应运而生,即将一个数据库表映射成一个类,简单说就是将与数据库的多种交互操作,封装成一个类,类里面包含之前的增删查改等操作方法。
2. 难点二:理解元类metaclass
metaclass(元类),继承自type,通俗来说是,用来创建类的类工厂,当一个类继承了某个元类,会调用元类中的方法初始化、创建类。
ModelMetaclass:类的元类,主要是为了将一个数据库表映射成类做准备工作。
3. 难点三:注意一步异步,处处异步
为了处理大量用户的请求,采用协程(只有一个线程,控制协程的切换),协程是异步的,所以不能采用一般的IO处理(速度太慢,严重影响协程),故采用面向mysql的异步Io:aiomysql。
其他细节都在下面代码的注释里,当然包括网友们的理解和自己的一些理解,详情见下方代码。
#orm.py
#coding:utf-8
#day3:ORM 对象关系映射:通俗说就是将一个数据库表映射为一个类
import sys,random
import asyncio
#一步异步,处处使用异步
import aiomysql
import logging
logging.basicConfig(level=logging.INFO)#日志记录
#日志打印函数:打印出使用的sql语句
def log(sql,args=()):
logging.info('SQL:%s'%sql)
#异步协程:创建数据库连接池
@asyncio.coroutine
def create_pool(loop,**kw):
logging.info('start creating database connection pool')
#全局私有变量,尽内部可以访问
global __pool
#yield from 调用协程函数并返回结果
__pool = yield from aiomysql.create_pool(
#kw.get(key,default):通过key在kw中查找对应的value,如果没有则返回默认值default
host = kw.get('host','localhost'),
port = kw.get('port',3306),
user = kw['user'],
password = kw['password'],
db = kw['db'],
charset = kw.get('charset','utf8'),
autocommit = kw.get('autocommit',True),
maxsize = kw.get('maxsize',10),
minsize = kw.get('minsize',1),
loop = loop
)
#协程:销毁所有的数据库连接池
async def destory_pool():
global __pool
if __pool is not None:
__pool.close()
await __pool.wait_closed()
#协程:面向sql的查询操作:size指定返回的查询结果数
@asyncio.coroutine
def select(sql,args,size=None):
log(sql,args)
global __pool
#yield from从连接池返回一个连接
with (yield from __pool) as conn:
#查询需要返回查询的结果,按照dict返回,所以游标cursor中传入了参数aiomysql.DictCursor
cur = yield from conn.cursor(aiomysql.DictCursor)
#执行sql语句前,先将sql语句中的占位符?换成mysql中采用的占位符%s
yield from cur.execute(sql.replace('?','%s'),args)
if size:
rs = yield from cur.fetchmany(size)
else:
rs = yield from cur.fetchall()
yield from cur.close()
logging.info('%s rows have returned' % len(rs))
return rs
#将面向mysql的增insert、删delete、改update封装成一个协程
#语句操作参数一样,直接封装成一个通用的执行函数
#返回受影响的行数
@asyncio.coroutine
def execute(sql,args,autocommit = True):
log(sql,args)
global __pool
with (