model.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. # -*- coding: utf-8 -*-
  2. """
  3. demeter
  4. name:model.py
  5. author:rabin
  6. """
  7. import os
  8. import uuid
  9. import short_url
  10. import json
  11. import traceback
  12. import re
  13. import math
  14. import datetime
  15. from demeter.core import *
  16. class Model(object):
  17. __table__ = ''
  18. __comment__ = ''
  19. def __init__(self, type, db, config):
  20. self.db = db
  21. self._type = type
  22. self._config = config
  23. self._set = ''
  24. self._bind = {}
  25. self._attr = {}
  26. self._key = {}
  27. self.call = False
  28. self.log = []
  29. self.sql = False
  30. self.bind = False
  31. self.place = '%s'
  32. if self._type == 'sqlite':
  33. self.place = '?'
  34. self.setTable(self.__table__)
  35. self.create()
  36. def setTable(self, name):
  37. if 'prefix' in self._config and self._config['prefix']:
  38. self._table = self._config['prefix'] + '_' + name
  39. else:
  40. self._table = name
  41. def setCall(self, call):
  42. self.call = call
  43. return self
  44. def addLog(self, value):
  45. self.log.append(value)
  46. def getLog(self):
  47. return self.log
  48. def cur(self):
  49. return self.db.cursor()
  50. def commit(self):
  51. return self.db.commit()
  52. def lastId(self, cur):
  53. if hasattr(cur, 'lastrowid'):
  54. id = cur.lastrowid
  55. if not id:
  56. id = cur.fetchone()[0]
  57. else:
  58. id = cur.fetchone()[0]
  59. return id
  60. def query(self, sql, bind=[], fetch='fetchone', method='', cur=False, call=False):
  61. if call:
  62. self.setCall(call)
  63. if not cur:
  64. cur = self.cur()
  65. if not method:
  66. if 'select' in sql:
  67. method = 'select'
  68. if 'insert' in sql:
  69. method = 'insert'
  70. self.sql = sql
  71. self.bind = bind
  72. self.addLog((sql, bind))
  73. try:
  74. cur.execute(sql, bind)
  75. if method == 'select':
  76. return self.fetch(cur, fetch)
  77. id = True
  78. if method == 'insert':
  79. id = self.lastId(cur)
  80. Demeter.sync(self._table, id)
  81. if method == 'update' and 'id' in self._bind:
  82. Demeter.sync(self._table, self._bind['id'])
  83. self.commit()
  84. except Exception as e:
  85. self.addLog(str(e))
  86. return False
  87. self._set = {}
  88. return id
  89. def execute(self, sql, method='select', fetch='fetchall'):
  90. cur = self.cur()
  91. bind = []
  92. state_true = True
  93. state_false = False
  94. if self._type == 'mysql':
  95. state_true = '1'
  96. state_false = '2'
  97. if self._set:
  98. for key in self._set:
  99. self.check(key, self._set[key], self._attr[key])
  100. if self._set[key] == 'time':
  101. self._set[key] = self.time()
  102. elif self._set[key] == 'True':
  103. self._set[key] = state_true
  104. elif self._set[key] == 'False':
  105. self._set[key] = state_false
  106. elif 'date' in key and type(self._set[key]) != int:
  107. self._set[key] = self.mktime(self._set[key])
  108. elif self._attr[key].md5:
  109. self._set[key] = self.createMd5(self._set[key])
  110. bind.append(self._set[key])
  111. for value in self._key:
  112. if value[0] in self._bind and self._bind[value[0]] != None:
  113. val = self._bind[value[0]]
  114. if method == 'insert':
  115. self.check(value[0], val, self._attr[value[0]])
  116. self._attr[value[0]].unset()
  117. if type(val) == list and val:
  118. for i in val:
  119. bind.append(i)
  120. else:
  121. bind.append(val)
  122. if method == 'select' and ';' in sql:
  123. temp = sql.split(';')
  124. sql = temp[1]
  125. totalSql = temp[0]
  126. cur.execute(totalSql, bind)
  127. Demeter.config['page']['totalNum'] = self.fetch(cur, 'fetchone', 'count')
  128. Demeter.config['page']['total'] = int(math.ceil(round(float(Demeter.config['page']['totalNum'])/float(Demeter.config['page']['num']),2)))
  129. elif ';' in sql:
  130. temp = sql.split(';')
  131. result = []
  132. for v in temp:
  133. result.append(self.query(v, (), fetch=fetch, method=method, cur=cur))
  134. return result
  135. return self.query(sql, bind, fetch=fetch, method=method, cur=cur)
  136. def fetchAll(self):
  137. return self.fetch(self.cur(), type='fetchall')
  138. def fetch(self, cur, type='fetchall', method = ''):
  139. load = getattr(cur, type)
  140. rows = load()
  141. desc = self._key
  142. desc = cur.description
  143. if type == 'fetchall':
  144. result = []
  145. if rows:
  146. for key in rows:
  147. row = {}
  148. i = 0
  149. for v in key:
  150. row[desc[i][0]] = self.data(desc[i][0], v)
  151. i = i + 1
  152. result.append(row)
  153. elif method == 'count':
  154. return rows[0]
  155. else:
  156. result = {}
  157. i = 0
  158. if rows:
  159. for v in rows:
  160. if not v:
  161. v = ''
  162. result[desc[i][0]] = self.data(desc[i][0], v)
  163. i = i + 1
  164. return result
  165. def data(self, key, value):
  166. if type(value) == datetime.datetime:
  167. value = str(value)
  168. if self.call:
  169. value = self.call(key, value)
  170. if value == None or not value:
  171. value = ''
  172. return value
  173. def attr(self, method):
  174. fields = vars(self.__class__)
  175. self._attr = {}
  176. self._bind = {}
  177. self._key = {}
  178. if Demeter.checkPy3():
  179. col = (int, str, float, bool, uuid.UUID)
  180. code = (str,)
  181. else:
  182. col = (int, str, long, float, unicode, bool, uuid.UUID)
  183. code = (str, unicode)
  184. for field in fields:
  185. if isinstance(fields[field], Fields):
  186. self._attr[field] = fields[field]
  187. self._key[field] = self._attr[field].getKey()
  188. insert = (method == 'insert')
  189. update = (insert or method == 'update')
  190. if insert and self._attr[field].uuid:
  191. self.setUuid(field, col)
  192. bind = False
  193. val = self._attr[field].getArgv()
  194. if val or val == False:
  195. bind = True
  196. else:
  197. val = getattr(self, field)
  198. if isinstance(val, col):
  199. setattr(self, field, self._attr[field])
  200. bind = True
  201. elif insert and self._attr[field].default:
  202. val = self._attr[field].default
  203. bind = True
  204. if val == 'time':
  205. val = self.time()
  206. elif '.' in val:
  207. temp = val.split('.')
  208. val = Demeter.config[temp[0]][temp[1]]
  209. elif method == 'select' and self._attr[field].default and field == 'state':
  210. val = self._attr[field].default
  211. bind = True
  212. if bind and val != None:
  213. if type(val) == list:
  214. length = len(val)
  215. if length <= 1:
  216. val = val[0]
  217. if insert and self._attr[field].md5:
  218. val = self.createMd5(val)
  219. if self._attr[field].type == 'boolean' and isinstance(val, code):
  220. val = Demeter.bool(val, self._type)
  221. if type(val) == list:
  222. val = tuple(val)
  223. self._bind[field] = val
  224. self._attr[field].val(self._bind[field])
  225. self._attr[field].bind(self.place)
  226. self._key = sorted(self._key.items(), key=lambda d:d[1], reverse = False)
  227. Counter().unset()
  228. def check(self, field, val, attr):
  229. if val == 'undefined':
  230. self.error(error)
  231. if attr.match == 'not':
  232. if not val:
  233. self.error(field + ' not exists')
  234. elif attr.match:
  235. if '|' in attr.match:
  236. temp = attr.match.split('|')
  237. match = temp[0]
  238. error = temp[1]
  239. else:
  240. match = attr.match
  241. error = field + ' not match:' + match
  242. if hasattr(Check, match):
  243. method = getattr(Check, match)
  244. result = method(val)
  245. else:
  246. result = re.search(match, val)
  247. if not result:
  248. self.error(error)
  249. def error(self, msg):
  250. for value in self._key:
  251. if value[0] in self._bind and self._bind[value[0]] != None:
  252. self._attr[value[0]].unset()
  253. self._set = {}
  254. Demeter.error(msg)
  255. def time(self):
  256. return Demeter.time()
  257. def mktime(self, value):
  258. return Demeter.mktime(value)
  259. def setUuid(self, field, col):
  260. id = getattr(self, self._attr[field].uuid)
  261. if isinstance(id, col):
  262. system = short_url.encode_url(id)
  263. else:
  264. system = self._attr[field].uuid
  265. name = system + '.' + self.__table__
  266. result = Demeter.uuid(name)
  267. setattr(self, field, result)
  268. def createMd5(self, value):
  269. if 'db_md5' in Demeter.config and Demeter.config['db_md5'] == 1:
  270. Demeter.config['db_md5'] = 2
  271. return value
  272. else:
  273. return Demeter.md5(value, salt=True)
  274. def createState(self):
  275. if 'create' in self._config:
  276. create = Demeter.bool(self._config['create'])
  277. if create:
  278. return Demeter.runtime(self._type, self.__table__, json.dumps(self._key))
  279. return False
  280. def drop(self):
  281. return self.handle('drop')
  282. def create(self):
  283. return self.handle('create')
  284. def insert(self):
  285. return self.handle('insert')
  286. def update(self, *args, **kwargs):
  287. if args:
  288. self._set = args[0]
  289. else:
  290. self._set = kwargs
  291. return self.handle('update', set=self._set)
  292. def delete(self):
  293. return self.handle('delete')
  294. def select(self, type='fetchall',col = '*', order = 'cdate desc', group = '', limit = '0,100', page=False, call=False):
  295. if call:
  296. self.setCall(call)
  297. pageConfig = {}
  298. if page and 'page' in Demeter.config:
  299. pageConfig['current'] = Demeter.config['page']['current']
  300. if page == True:
  301. pageConfig['num'] = 15
  302. elif 'num' in page:
  303. pageConfig['num'] = page['num']
  304. Demeter.config['page']['num'] = pageConfig['num']
  305. return self.handle('select', type=type, col=col, order=order, group=group, limit=limit, page=pageConfig)
  306. def manage(self):
  307. self.attr(method)
  308. return
  309. def handle(self, method='select', type='fetchall', col = '*', order = '', group = '', limit = '0,100', page=False, set = ''):
  310. self.attr(method)
  311. if method == 'create':
  312. create = self.createState()
  313. if create == False:
  314. return False
  315. if type == 'fetchone':
  316. limit = '0,1'
  317. load = getattr(Sql(self._type, self.place), method)
  318. return self.execute(load(self._table, {'key':self._key, 'fields':self._attr, 'col':col, 'order':order, 'group':group, 'limit':limit, 'page':page, 'set':set, 'table_comment':self.__comment__}), method, type)
  319. class Fields(object):
  320. def __init__(self, type='', default='', primaryKey=False, autoIncrement=False, null=True, unique=False, check='', constraint='', comment='', uuid='', index=False, indexs=False, md5=False, match='', manage=''):
  321. self.type = type
  322. self.default = default
  323. self.primaryKey = primaryKey
  324. self.autoIncrement = autoIncrement
  325. self.null = null
  326. self.unique = unique
  327. self.check = check
  328. self.constraint = constraint
  329. self.comment = comment
  330. self.uuid = uuid
  331. self.index = index
  332. self.indexs = indexs
  333. self.md5 = md5
  334. self.key = Counter().inc()
  335. self.match = match
  336. self.value = ''
  337. self.argv = ''
  338. self.bindValue = ''
  339. self.expValue = '='
  340. self.logicValue = 'and'
  341. self.manage = manage
  342. # set value
  343. def assign(self, value, exp='=', logic='and'):
  344. self.add(value)
  345. self.exp(exp)
  346. self.logic(logic)
  347. return self
  348. def ins(self, value):
  349. self.argv = value
  350. self.exp('in')
  351. return self
  352. def nq(self, value):
  353. self.argv = value
  354. self.exp('!=')
  355. return self
  356. def like(self, value):
  357. self.argv = '%' + value + '%'
  358. self.exp('like')
  359. return self
  360. def mlike(self, value):
  361. self.argv = value
  362. self.exp('~')
  363. self.logic('and')
  364. return self
  365. def time(self, value):
  366. self.add(Demeter.mktime(value))
  367. return self
  368. def start(self, value):
  369. self.time(value)
  370. self.exp('>=')
  371. self.logic('and')
  372. return self
  373. def end(self, value):
  374. self.time(value)
  375. self.exp('<=')
  376. self.logic('and')
  377. return self
  378. def bind(self, value):
  379. self.bindValue = value
  380. return self
  381. def exp(self, value):
  382. """
  383. if type(self.expValue) != list:
  384. self.expValue = []
  385. self.expValue.append(value)
  386. """
  387. self.expValue = value
  388. return self
  389. def logic(self, value):
  390. """
  391. if type(self.logicValue) != list:
  392. self.logicValue = []
  393. self.logicValue.append(value)
  394. """
  395. self.logicValue = value
  396. return self
  397. def val(self, value, exp='=', logic='and'):
  398. if type(value) == list:
  399. length = len(value)
  400. if length <= 1:
  401. value = value[0]
  402. self.value = value
  403. if not self.expValue:
  404. self.exp(exp)
  405. if not self.logicValue:
  406. self.logic(logic)
  407. return self
  408. def getArgv(self):
  409. return self.argv
  410. def getVal(self):
  411. return self.value
  412. def getBind(self):
  413. return self.bindValue
  414. def getExp(self):
  415. if not self.expValue:
  416. return ''
  417. if type(self.expValue) == list:
  418. length = len(self.expValue)
  419. if length <= 1:
  420. result = self.expValue[0]
  421. else:
  422. result = self.expValue
  423. else:
  424. result = self.expValue
  425. return result
  426. def getKey(self):
  427. return self.key
  428. def getLogic(self):
  429. if not self.logicValue:
  430. return ''
  431. if type(self.logicValue) == list:
  432. length = len(self.logicValue)
  433. if length <= 1:
  434. result = self.logicValue[0]
  435. else:
  436. result = self.logicValue
  437. else:
  438. result = self.logicValue
  439. return result
  440. def unset(self):
  441. self.argv = None
  442. self.value = None
  443. self.bindValue = None
  444. self.expValue = '='
  445. self.logicValue = 'and'
  446. return self
  447. def add(self, value):
  448. """
  449. if not self.argv:
  450. self.argv = []
  451. self.argv.append(value)
  452. """
  453. self.argv = value
  454. return self
  455. class Counter(object):
  456. num = 0
  457. """
  458. instance = None
  459. def __new__(cls, *args, **kwd):
  460. if Counter.instance is None:
  461. Counter.instance = object.__new__(cls, *args, **kwd)
  462. return Counter.instance
  463. """
  464. def inc(self):
  465. self.num = self.num + 1
  466. return self.num
  467. def dec(self):
  468. self.num = self.num - 1
  469. return self.num
  470. def unset(self):
  471. self.num = 0
  472. return self.num
  473. class Sql(object):
  474. """
  475. instance = None
  476. def __new__(cls, *args, **kwd):
  477. if Sql.instance is None:
  478. Sql.instance = object.__new__(cls, *args, **kwd)
  479. return Sql.instance
  480. """
  481. def __init__(self, type, place):
  482. self.type = type
  483. self.place = place
  484. self.prefix = '`'
  485. if self.type == 'postgresql':
  486. self.prefix = ''
  487. def drop(self, table, args):
  488. sql = 'DROP TABLE IF EXISTS ' + table
  489. return sql
  490. def alter(self, table, args):
  491. sql = 'ALTER TABLE ' + table + ' ADD COLUMN '
  492. return sql
  493. def create(self, table, args):
  494. create = []
  495. primary = []
  496. unique = []
  497. indexs = []
  498. index = []
  499. comment = {}
  500. for value in args['key']:
  501. key = value[0]
  502. val = args['fields'][key]
  503. if val.primaryKey:
  504. primary.append(key)
  505. if val.unique:
  506. unique.append(key)
  507. if val.index:
  508. index.append((key, val.index))
  509. if val.indexs:
  510. indexs.append(key)
  511. fields = []
  512. fields.append(self.prefix + key + self.prefix)
  513. if val.autoIncrement and self.type == 'postgresql':
  514. fields.append('SERIAL')
  515. elif self.type == 'mysql' and val.type == 'boolean':
  516. fields.append('int')
  517. elif self.type == 'sqlite' and val.type == 'int':
  518. if val.autoIncrement and val.primaryKey:
  519. fields.append('integer PRIMARY KEY autoincrement')
  520. else:
  521. fields.append('integer')
  522. else:
  523. fields.append(val.type)
  524. if not val.null:
  525. fields.append('NOT NULL')
  526. if val.autoIncrement and self.type == 'mysql':
  527. fields.append('AUTO_INCREMENT')
  528. #约束
  529. if val.constraint:
  530. fields.append('CONSTRAINT ' + val.constraint)
  531. if val.check:
  532. fields.append('CHECK ' + val.check)
  533. if val.default:
  534. default = val.default
  535. if val.default == 'time':
  536. default = '0'
  537. if '.' in val.default:
  538. temp = val.default.split('.')
  539. default = Demeter.config[temp[0]][temp[1]]
  540. if self.type == 'mysql' and val.type == 'boolean':
  541. default = Demeter.bool(default, self.type)
  542. fields.append('DEFAULT \'' + str(default) + '\'')
  543. if val.comment:
  544. if self.type == 'mysql':
  545. fields.append('COMMENT \'' + val.comment + '\'')
  546. else:
  547. comment[key] = val.comment
  548. fields = ' '.join(fields)
  549. create.append(fields)
  550. if primary and self.type != 'sqlite':
  551. create.append('PRIMARY KEY (' + ','.join(primary) + ')')
  552. if unique:
  553. create.append('UNIQUE (' + ','.join(unique) + ')')
  554. create = ','.join(create)
  555. sql = 'CREATE TABLE ' + table + '(' + create + ')'
  556. sql = self.drop(table, args) + ';' + sql
  557. if indexs:
  558. name = '_'.join(indexs)
  559. value = ','.join(indexs)
  560. sql = sql + ';' + 'CREATE INDEX ' + table + '_' + name +' ON ' + table + '(' + value + ')'
  561. if index:
  562. for value in index:
  563. sql = sql + ';' + 'CREATE INDEX ' + table + '_' + value[0] +' ON ' + table + value[1]
  564. if comment and self.type != 'sqlite':
  565. if args['table_comment']:
  566. sql = sql + ';' + 'COMMENT ON TABLE ' + table + ' IS \''+args['table_comment']+'\''
  567. for key in comment:
  568. sql = sql + ';' + 'COMMENT ON COLUMN ' + table + '.'+key+' IS \''+comment[key]+'\''
  569. return sql
  570. def insert(self, table, args):
  571. fields = []
  572. values = []
  573. for value in args['key']:
  574. key = value[0]
  575. val = args['fields'][key].getBind()
  576. if val:
  577. values.append(val)
  578. fields.append(self.prefix + key + self.prefix)
  579. fields = ','.join(fields)
  580. values = ','.join(values)
  581. sql = 'INSERT INTO ' + table + ' (' + fields + ') VALUES (' + values + ')'
  582. if self.type == 'postgresql':
  583. sql = sql + ' RETURNING id'
  584. return sql
  585. def update(self, table, args):
  586. fields = []
  587. for key in args['set']:
  588. fields.append(self.prefix + key + self.prefix + ' = ' + self.place)
  589. fields = ','.join(fields)
  590. sql = 'UPDATE ' + table + ' SET ' + fields + self.where(args['key'], args['fields'])
  591. return sql
  592. def delete(self, table, args):
  593. sql = 'DELETE FROM ' + table + self.where(args['key'], args['fields'])
  594. return sql
  595. def select(self, table, args):
  596. string = ' FROM ' + table + self.where(args['key'], args['fields']) + ' ' + self.group(args['group'])
  597. sql = ''
  598. if args['page']:
  599. sql = 'SELECT count(1) as total' + string + ';'
  600. sql = sql + 'SELECT ' + args['col'] + string + ' ' + self.order(args['order']) + ' ' + self.limit(args['limit'], args['page'])
  601. return sql
  602. def where(self, key, fields):
  603. fields = self.fields(key, fields)
  604. if fields:
  605. return ' WHERE ' + fields
  606. return ''
  607. def fields(self, key, fields):
  608. result = ''
  609. k = 0
  610. for value in key:
  611. key = value[0]
  612. field = fields[key]
  613. bind = field.getBind()
  614. val = field.getVal()
  615. logic = field.getLogic()
  616. exp = field.getExp()
  617. if type(val) == list and val:
  618. n = 0
  619. for i in val:
  620. data = self.field(field, bind, key, k, logic[n], exp[n])
  621. n = n + 1
  622. if data:
  623. result = result + data
  624. k = 1
  625. else:
  626. data = self.field(field, bind, key, k, logic, exp)
  627. if data:
  628. result = result + data
  629. k = 1
  630. return result
  631. def field(self, field, val, key, k, logic, exp):
  632. result = ''
  633. if val:
  634. if k == 0:
  635. logic = ''
  636. else:
  637. logic = ' ' + logic
  638. result = logic + ' ' + self.prefix + key + self.prefix + ' ' + exp + ' ' + str(val)
  639. return result
  640. def order(self, value):
  641. result = ''
  642. if value:
  643. result = ' ORDER BY ' + value
  644. return result
  645. def group(self, value):
  646. result = ''
  647. if value:
  648. result = ' GROUP BY ' + value
  649. return result
  650. def limit(self, value, page):
  651. result = ''
  652. if page:
  653. value = str((int(page['current'])-1) * page['num']) + ',' + str(page['num'])
  654. if value:
  655. value = value.split(',')
  656. if self.type == 'mysql':
  657. result = ' LIMIT ' + value[0] + ',' + value[1]
  658. elif self.type == 'postgresql':
  659. result = ' LIMIT ' + value[1] + ' OFFSET ' + value[0]
  660. return result