18 Star 17 Fork 1

thanatosx / WebBlog

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
orm.py 11.87 KB
一键复制 编辑 原始数据 按行查看 历史
mxxim 提交于 2015-07-03 10:49 . 。。
from base import Page
__author__ = 'thanatos'
import logging;
logging.basicConfig(level=logging.INFO)
import asyncio
import exception as exception
import dao
class Field(object):
domains = {}
def __init__(self, name, column_type, primary_key, default, transfer=None):
"""
:param name: what's name in database
:param column_type: what's name in table in database
:param primary_key: is it primary key?
:param default: default value
:return:
"""
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default = default
self.transfer = transfer or (lambda v: v if v is None else str(v))
class StringField(Field):
def __init__(self, name=None, length=20, primary_key=False, default=None):
super().__init__(name, 'varchar(%s)' % length, primary_key, default)
class TextField(Field):
def __init__(self, name=None, default=None):
super().__init__(name, 'longtext', False, default)
class BooleanField(Field):
def __init__(self, name=None, primary_key=False, default=False):
super().__init__(name, 'boolean', primary_key, default, transfer=lambda v: v if v is None else bool(ord(v)))
class LongField(Field):
def __init__(self, name=None, primary_key=False, default=None):
super().__init__(name, 'long', primary_key, default, transfer=lambda v: v if v is None else int(v))
class IntegerField(Field):
def __init__(self, name=None, primary_key=False, default=None):
super().__init__(name, 'int', primary_key, default, transfer=lambda v: v if v is None else int(v))
class FloatField(Field):
def __init__(self, name=None, primary_key=False, default=None):
super().__init__(name, 'float', primary_key, default, transfer=lambda v: v if v is None else float(v))
class ModelField(Field):
"""Many To One
"""
def __init__(self, model, name=None, primary_key=False, default=None):
self.model = model
super().__init__(name, 'long', primary_key, default, transfer=self.transfer)
@asyncio.coroutine
def transfer(self, mid):
if isinstance(self.model, str):
self.model = getattr(__import__(Field.domains[self.model], globals(), locals()), self.model)
if not isinstance(self.model, ModelMetaClass):
raise ValueError('%s is not subclass of Model' % self.model)
return (yield from self.model.find(mid))
class MultiField(Field):
"""Many To Many or One To Many
"""
def __init__(self, mapped_key, model, another_key=None, table=None):
"""
:param mapped_key: One 的一方
:param another_key: Many的一方
:param model: Many的一方对应的实体
:param table: 第三方表,没有表示One To Many
:return:
"""
self.model = model
self.table = table
self.mapped_key = mapped_key
self.another_key = another_key
super().__init__(None, 'long', False, None, self.transfer)
@asyncio.coroutine
def transfer(self, mid):
if isinstance(self.model, str):
self.model = getattr(__import__(Field.domains[self.model], globals(), locals()), self.model)
if not isinstance(self.model, ModelMetaClass):
raise ValueError('%s is not subclass of Model' % self.model)
if self.table and self.another_key:
sql = 'SELECT r.* FROM %s AS ur JOIN %s AS r ON r.%s = ur.%s AND ur.%s=?' % \
(self.table, self.model.__table__, self.model.__key__, self.another_key, self.mapped_key)
else:
sql = 'SELECT * FROM %s WHERE %s=?' % (self.model.__table__, self.mapped_key)
return self.model.select(mid, sql=sql, fetchable=False, cascade=False)
class ModelMetaClass(type):
def __new__(mcs, name, bases, attrs):
if name == 'Model':
return type.__new__(mcs, name, bases, attrs)
Field.domains[name] = attrs['__module__']
table = attrs.get('__table__', None) or name
mappings = dict()
field_mappings = dict()
primary_key = None
key = None
for k, v in attrs.items():
if isinstance(v, Field):
mappings[k] = v
v.name = v.name or k
if v.primary_key:
if primary_key:
raise exception.DuplicateError('There has Duplicate primary key')
primary_key = v
key = k
else:
if not isinstance(v, MultiField):
field_mappings[k] = v.name
if not primary_key:
raise ValueError("excepting a primary key but got nothing")
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings
attrs['__field_mappings__'] = field_mappings
attrs['__table__'] = table
attrs['__key__'] = key
attrs['__primary_key__'] = primary_key
attrs['__save__'] = 'INSERT INTO %s(%s) VALUES(%s)' % (
table, ','.join(field_mappings.values()), ','.join('?' * len(field_mappings)))
attrs['__delete__'] = 'DELETE FROM %s WHERE %s=?' % (table, primary_key.name)
attrs['__select__'] = 'SELECT * FROM %s' % table
attrs['__count__'] = 'SELECT COUNT(*) AS count FROM %s' % table
attrs['__unique__'] = 'SELECT * FROM %s WHERE %s=?' % (table, primary_key.name)
attrs['__update__'] = 'UPDATE %s' % table
attrs['__update_all__'] = 'UPDATE %s SET %s WHERE %s=?' % (
table, ','.join(list(map(lambda f: '%s=?' % f, field_mappings.values()))), primary_key.name)
return type.__new__(mcs, name, bases, attrs)
class Model(dict, metaclass=ModelMetaClass):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def __getattr__(self, item):
try:
return self[item]
except KeyError:
return None
def __setattr__(self, key, value):
self[key] = value
def __str__(self):
return self.__class__.__name__ + '{' + ', '.join(
list(map(lambda k: '%s: %s' % (k, self.getValue(k)), self.__mappings__.keys()))) + '}'
__repr__ = __str__
def remove(self, *args):
"""
删除指定的字段
:param args:
:return:
"""
for k in args:
try:
del self[k]
except KeyError:
logging.warning('There has not this key here')
def reserve(self, *args):
"""
只留下需要的属性
:param args:
:return:
"""
for k in self.__mappings__.keys():
if k not in args and getattr(self, k, None) is not None:
del self[k]
def getValue(self, key):
return getattr(self, key, None)
def getValueOfDefault(self, key):
value = self.getValue(key)
if value is None:
field = self.__mappings__[key]
if field is not None and field.default is not None:
value = field.default
self.__setattr__(key, value)
return value
def extend(self, **kwargs):
for k, v in kwargs.items():
self[k] = v
@asyncio.coroutine
def save(self):
args = list(map(self.getValueOfDefault, self.__field_mappings__.keys()))
_id = yield from dao.execute(self.__save__, args, is_insert=True)
self[self.__key__] = _id
@asyncio.coroutine
def prune(self):
key_value = getattr(self, self.__primary_key__.name, None)
if not key_value:
raise ValueError('key value not found')
rows = yield from dao.execute(self.__delete__, key_value)
logging.info('prune effected :%s', rows)
@asyncio.coroutine
def renew(self, *fields):
"""
用户信息更新,与dict的update方法区别开来
:param fields:
:return:
"""
sql = []
if fields:
sql.append(self.__update__)
sql.append('SET')
sql.append(','.join(list(map(lambda v: '%s=?' % v, [self.__field_mappings__[k] for k in fields]))))
sql.append('WHERE %s=?' % self.__key__)
args = [self.getValueOfDefault(k) for k in fields] + [self.getValueOfDefault(self.__key__)]
else:
sql.append(self.__update_all__)
args = [self.getValueOfDefault(k) for k in self.__field_mappings__.keys()] + [
self.getValueOfDefault(self.__key__)]
logging.info('update --> %s ' % ' '.join(sql))
yield from dao.execute(' '.join(sql), args)
@classmethod
@asyncio.coroutine
def select(cls, *args, sql=None, size=None, fetchable=False, cascade=False):
rows = yield from dao.select(sql or cls.__select__, args, size)
return (yield from cls.transfer(rows, fetchable, cascade))
@classmethod
@asyncio.coroutine
def transfer(cls, kwargs, fetchable, cascade):
o = None
if isinstance(kwargs, dict):
o = cls()
for k, v in cls.__mappings__.items():
if cascade and isinstance(v, MultiField) and kwargs.get(cls.__key__):
value = yield from v.transfer(kwargs.get(cls.__key__))
if value:
o[k] = value
else:
value = kwargs.get(v.name)
if value is not None:
if isinstance(v, ModelField):
if fetchable:
o[k] = yield from v.transfer(value)
else:
o[k] = v.transfer(value)
if isinstance(kwargs, list):
o = list()
for v in kwargs:
value = yield from cls.transfer(v, fetchable, cascade)
o.append(value)
return o
@classmethod
@asyncio.coroutine
def findAll(cls, *args, where=None, fetchable=False, cascade=False):
sql = [cls.__select__]
if where:
sql.append('WHERE')
sql.append(where)
logging.info('findAll sql --> %s' % sql)
values = yield from dao.select(' '.join(sql), args)
return (yield from cls.transfer(values, fetchable, cascade))
@classmethod
@asyncio.coroutine
def find(cls, uid, fetchable=False, cascade=False):
if not uid:
return None
logging.info("find sql --> %s" % cls.__unique__)
values = yield from dao.select(cls.__unique__, uid)
if len(values) <= 0:
return None
return (yield from cls.transfer(values[0], fetchable, cascade))
@classmethod
@asyncio.coroutine
def page(cls, *args, select_sql=None, count_sql=None, where=None, current=1, size=10, fetchable=False,
cascade=False):
sqls = []
if count_sql:
sqls.append(count_sql)
else:
sqls.append(cls.__count__)
if where:
sqls.append('WHERE')
sqls.append(where)
count = yield from dao.select(' '.join(sqls), args)
records = count[0]['count']
sqls = []
if select_sql:
sqls.append(select_sql)
else:
sqls.append(cls.__select__)
if where:
sqls.append('WHERE')
sqls.append(where)
sqls.append('LIMIT ?,?')
args = args + ((current - 1) * size, size)
values = yield from dao.select(' '.join(sqls), args)
values = yield from cls.transfer(values, fetchable, cascade)
return Page(current, size, records, values)
@classmethod
@asyncio.coroutine
def count(cls, *args, where=None, sql=None):
if sql is None:
sqls = ['SELECT count(*) FROM %s' % cls.__table__]
if where:
sqls.append('WHERE')
sqls.append(where)
sql = ' '.join(sqls)
count = yield from dao.select(sql, args)
return count[0]['count'] if count else 0
Python
1
https://gitee.com/handoop/WebBlog.git
git@gitee.com:handoop/WebBlog.git
handoop
WebBlog
WebBlog
master

搜索帮助