orm.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import json
  4. import jimit as ji
  5. from mysql.connector import errorcode, errors
  6. from database import Database as db
  7. from jimvc.models import Filter
  8. __author__ = 'James Iter'
  9. __date__ = '2017/3/23'
  10. __contact__ = 'james.iter.cn@gmail.com'
  11. __copyright__ = '(c) 2017 by James Iter.'
  12. class ORM(object):
  13. _table_name = None
  14. _primary_key = None
  15. def __init__(self):
  16. pass
  17. def create(self):
  18. sql_stmt = ("INSERT INTO " + self._table_name + " (" +
  19. ', '.join(filter(lambda _key: _key != self._primary_key, self.__dict__.keys())) +
  20. ") VALUES (" +
  21. ', '.join(['%({0})s'.format(key)
  22. for key in filter(lambda _key: _key != self._primary_key, self.__dict__.keys())]) + ")")
  23. cnx = db.cnxpool.get_connection()
  24. cursor = cnx.cursor(dictionary=True, buffered=True)
  25. try:
  26. cursor.execute(sql_stmt, self.__dict__)
  27. self.__setattr__(self._primary_key, cursor.lastrowid)
  28. cnx.commit()
  29. except errors.IntegrityError, e:
  30. ret = dict()
  31. if e.errno == errorcode.ER_DUP_ENTRY:
  32. ret['state'] = ji.Common.exchange_state(40901)
  33. elif e.errno == errorcode.ER_BAD_NULL_ERROR:
  34. ret['state'] = ji.Common.exchange_state(41202)
  35. else:
  36. ret['state'] = ji.Common.exchange_state(50002)
  37. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', e.msg])
  38. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  39. finally:
  40. cursor.close()
  41. cnx.close()
  42. def update(self):
  43. if not self.exist():
  44. ret = dict()
  45. ret['state'] = ji.Common.exchange_state(40401)
  46. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', self._primary_key.__str__()])
  47. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  48. sql_stmt = ("UPDATE " + self._table_name + " SET " +
  49. ', '.join(['{0} = %({0})s'.format(key)
  50. for key in filter(lambda _key: _key != self._primary_key, self.__dict__.keys())]) +
  51. " WHERE " + '{0} = %({0})s'.format(self._primary_key))
  52. cnx = db.cnxpool.get_connection()
  53. cursor = cnx.cursor(dictionary=True, buffered=True)
  54. try:
  55. cursor.execute(sql_stmt, self.__dict__)
  56. cnx.commit()
  57. except errors.IntegrityError, e:
  58. ret = dict()
  59. if e.errno == errorcode.ER_DUP_ENTRY:
  60. ret['state'] = ji.Common.exchange_state(40901)
  61. elif e.errno == errorcode.ER_BAD_NULL_ERROR:
  62. ret['state'] = ji.Common.exchange_state(41202)
  63. else:
  64. ret['state'] = ji.Common.exchange_state(50002)
  65. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', e.msg])
  66. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  67. finally:
  68. cursor.close()
  69. cnx.close()
  70. def delete(self):
  71. if not self.exist():
  72. ret = dict()
  73. ret['state'] = ji.Common.exchange_state(40401)
  74. ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', self._primary_key.__str__()])
  75. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  76. sql_stmt = ("DELETE FROM " + self._table_name + " WHERE " + '{0} = %({0})s'.format(self._primary_key))
  77. cnx = db.cnxpool.get_connection()
  78. cursor = cnx.cursor(dictionary=True, buffered=True)
  79. try:
  80. cursor.execute(sql_stmt, self.__dict__)
  81. cnx.commit()
  82. finally:
  83. cursor.close()
  84. cnx.close()
  85. def get(self):
  86. sql_stmt = ("SELECT " + ', '.join(self.__dict__.keys()) + " FROM " + self._table_name +
  87. " WHERE " + '{0} = %({0})s'.format(self._primary_key) +
  88. " LIMIT 1")
  89. cnx = db.cnxpool.get_connection()
  90. cursor = cnx.cursor(dictionary=True, buffered=True)
  91. try:
  92. cursor.execute(sql_stmt, self.__dict__)
  93. row = cursor.fetchone()
  94. finally:
  95. cursor.close()
  96. cnx.close()
  97. if isinstance(row, dict):
  98. self.__dict__ = row
  99. else:
  100. ret = dict()
  101. ret['state'] = ji.Common.exchange_state(40401)
  102. ret['state']['sub']['zh-cn'] = ': '.join([ret['state']['sub']['zh-cn'], self._primary_key,
  103. self.__getattribute__(self._primary_key).__str__()])
  104. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  105. def exist(self):
  106. sql_stmt = ("SELECT " + self._primary_key + " FROM " + self._table_name +
  107. " WHERE " + '{0} = %({0})s'.format(self._primary_key) + " LIMIT 1")
  108. cnx = db.cnxpool.get_connection()
  109. cursor = cnx.cursor(dictionary=True, buffered=True)
  110. try:
  111. cursor.execute(sql_stmt, self.__dict__)
  112. row = cursor.fetchone()
  113. finally:
  114. cursor.close()
  115. cnx.close()
  116. if isinstance(row, dict):
  117. return True
  118. return False
  119. def get_by(self, field):
  120. sql_stmt = ("SELECT " + ', '.join(self.__dict__.keys()) +
  121. " FROM " + self._table_name + " WHERE " + '{0} = %({0})s'.format(field) + " LIMIT 1")
  122. cnx = db.cnxpool.get_connection()
  123. cursor = cnx.cursor(dictionary=True, buffered=True)
  124. try:
  125. cursor.execute(sql_stmt, self.__dict__)
  126. row = cursor.fetchone()
  127. finally:
  128. cursor.close()
  129. cnx.close()
  130. if isinstance(row, dict):
  131. self.__dict__ = row
  132. else:
  133. ret = dict()
  134. ret['state'] = ji.Common.exchange_state(40401)
  135. ret['state']['sub']['zh-cn'] = ': '.join([ret['state']['sub']['zh-cn'], field.__str__(),
  136. self.__getattribute__(field).__str__()])
  137. raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))
  138. def exist_by(self, field):
  139. sql_field = field + ' = %(' + field + ')s'
  140. sql_stmt = ("SELECT " + self._primary_key + " FROM " + self._table_name + " WHERE " + sql_field + " LIMIT 1")
  141. cnx = db.cnxpool.get_connection()
  142. cursor = cnx.cursor(dictionary=True, buffered=True)
  143. try:
  144. cursor.execute(sql_stmt, self.__dict__)
  145. row = cursor.fetchone()
  146. finally:
  147. cursor.close()
  148. cnx.close()
  149. if isinstance(row, dict):
  150. return True
  151. return False
  152. @staticmethod
  153. def get_filter_keywords():
  154. # 指定参与过滤的关键字及其数据库对应字段类型
  155. """
  156. 使用示例
  157. return {
  158. 'name': FilterFieldType.STR.value,
  159. 'remark': FilterFieldType.STR.value,
  160. 'age': FilterFieldType.INT.value
  161. }
  162. """
  163. raise NotImplementedError()
  164. @classmethod
  165. def get_by_filter(cls, offset=0, limit=1000, order_by=None, order='asc', filter_str=''):
  166. if order_by is None:
  167. order_by = cls._primary_key
  168. sql_stmt = ("SELECT * FROM " + cls._table_name + " ORDER BY " + order_by + " " + order +
  169. " LIMIT %(offset)s, %(limit)s")
  170. sql_stmt_count = ("SELECT count(" + cls._primary_key + ") FROM " + cls._table_name)
  171. where_str = Filter.filter_str_to_sql(allow_keywords=cls.get_filter_keywords(), filter_str=filter_str)
  172. if where_str != '':
  173. sql_stmt = ("SELECT * FROM " + cls._table_name + " WHERE " + where_str + " ORDER BY " + order_by + " " +
  174. order + " LIMIT %(offset)s, %(limit)s")
  175. sql_stmt_count = ("SELECT count(" + cls._primary_key + ") FROM " + cls._table_name + " WHERE " + where_str)
  176. cnx = db.cnxpool.get_connection()
  177. cursor = cnx.cursor(dictionary=True, buffered=True)
  178. try:
  179. cursor.execute(sql_stmt, {'offset': offset, 'limit': limit})
  180. rows = cursor.fetchall()
  181. cursor.execute(sql_stmt_count)
  182. count = cursor.fetchone()
  183. return rows, count["count(" + cls._primary_key + ")"]
  184. finally:
  185. cursor.close()
  186. cnx.close()
  187. @staticmethod
  188. def get_allow_update_keywords():
  189. # 指定允许批量更新的字段
  190. """
  191. 使用示例
  192. return ['remark', 'age']
  193. """
  194. raise NotImplementedError()
  195. @classmethod
  196. def update_by_filter(cls, kv, filter_str=''):
  197. # 过滤掉不予支持批量更新的字段
  198. _kv = {}
  199. for k, v in kv.iteritems():
  200. if k in cls.get_allow_update_keywords():
  201. _kv[k] = v
  202. if _kv.__len__() < 1:
  203. return
  204. # set_str = ', '.join(map(lambda x: x + ' = %(' + x + ')s', _kv.keys()))
  205. # 上面为通过map实现的方式
  206. set_str = ', '.join(['{0} = %({0})s'.format(key) for key in _kv.keys()])
  207. where_str = Filter.filter_str_to_sql(allow_keywords=cls.get_filter_keywords(), filter_str=filter_str)
  208. sql_stmt = ("UPDATE " + cls._table_name + " SET " + set_str + " WHERE " + where_str)
  209. cnx = db.cnxpool.get_connection()
  210. cursor = cnx.cursor(dictionary=True, buffered=True)
  211. try:
  212. cursor.execute(sql_stmt, _kv)
  213. cnx.commit()
  214. finally:
  215. cursor.close()
  216. cnx.close()
  217. @classmethod
  218. def delete_by_filter(cls, filter_str=''):
  219. where_str = Filter.filter_str_to_sql(allow_keywords=cls.get_filter_keywords(), filter_str=filter_str)
  220. sql_stmt = ("DELETE FROM " + cls._table_name + " WHERE " + where_str)
  221. cnx = db.cnxpool.get_connection()
  222. cursor = cnx.cursor(dictionary=True, buffered=True)
  223. try:
  224. cursor.execute(sql_stmt)
  225. cnx.commit()
  226. finally:
  227. cursor.close()
  228. cnx.close()
  229. @staticmethod
  230. def get_allow_content_search_keywords():
  231. # 指定允许全文检索的字段
  232. """
  233. 使用示例
  234. return ['name', 'remark']
  235. """
  236. raise NotImplementedError()
  237. @classmethod
  238. def content_search(cls, offset=0, limit=1000, order_by=None, order='asc', filter_str='', keyword=''):
  239. if order_by is None:
  240. order_by = cls._primary_key
  241. _kv = dict()
  242. _kv = _kv.fromkeys(cls.get_allow_content_search_keywords(), '%{0}%'.format(keyword))
  243. where_str = ' OR '.join([k + ' LIKE %(' + k + ')s' for k in _kv.keys()])
  244. filter_str = Filter.filter_str_to_sql(allow_keywords=cls.get_filter_keywords(), filter_str=filter_str)
  245. if filter_str != '':
  246. where_str = filter_str + ' AND (' + where_str + ')'
  247. sql_stmt = ("SELECT * FROM " + cls._table_name + " WHERE " + where_str + " ORDER BY " + order_by + " " + order +
  248. " LIMIT %(offset)s, %(limit)s")
  249. sql_stmt_count = ("SELECT count(" + cls._primary_key + ") FROM " + cls._table_name + " WHERE " + where_str)
  250. _kv.update({'offset': offset, 'limit': limit})
  251. cnx = db.cnxpool.get_connection()
  252. cursor = cnx.cursor(dictionary=True, buffered=True)
  253. try:
  254. cursor.execute(sql_stmt, _kv)
  255. rows = cursor.fetchall()
  256. cursor.execute(sql_stmt_count, _kv)
  257. count = cursor.fetchone()
  258. return rows, count["count(" + cls._primary_key + ")"]
  259. finally:
  260. cursor.close()
  261. cnx.close()
  262. @classmethod
  263. def get_all(cls, order_by=None, order='asc'):
  264. if order_by is None:
  265. order_by = cls._primary_key
  266. sql_stmt = ("SELECT * FROM " + cls._table_name + " ORDER BY " + order_by + " " + order)
  267. sql_stmt_count = ("SELECT count(" + cls._primary_key + ") FROM " + cls._table_name)
  268. cnx = db.cnxpool.get_connection()
  269. cursor = cnx.cursor(dictionary=True, buffered=True)
  270. try:
  271. cursor.execute(sql_stmt)
  272. rows = cursor.fetchall()
  273. cursor.execute(sql_stmt_count)
  274. count = cursor.fetchone()
  275. return rows, count["count(" + cls._primary_key + ")"]
  276. finally:
  277. cursor.close()
  278. cnx.close()
  279. @classmethod
  280. def distinct_by(cls, fields=None, order_by=None, order='asc'):
  281. if order_by is None:
  282. order_by = cls._primary_key
  283. assert isinstance(fields, list)
  284. sql_stmt = ("SELECT DISTINCT " + ', '.join(fields) + " FROM " + cls._table_name +
  285. " ORDER BY " + order_by + " " + order)
  286. cnx = db.cnxpool.get_connection()
  287. cursor = cnx.cursor(dictionary=True, buffered=True)
  288. try:
  289. cursor.execute(sql_stmt)
  290. rows = cursor.fetchall()
  291. return rows, rows.__len__()
  292. finally:
  293. cursor.close()
  294. cnx.close()