batch_insert_util.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # -*- coding: utf-8 -*-
  2. from datetime import datetime, date
  3. import sys
  4. class BatchInsertUtil:
  5. __env = None # odoo的运行环境
  6. __cr = None # odoo的数据库环境
  7. __insert_model_name = '' # 要插入的模型全称<str> eg:'module_name.model_name'
  8. __insert_model_fields = [] # 要插入的字段名称<list> eg:['field_name_1', 'field_name_2', ...]
  9. __insert_values = [] # 要插入的值<list<dict>>
  10. __insert_values_keys = [] # 要插入的值的键值<list>,要按顺序与insert_model_fields保持一致
  11. __foreign_key_field_dict = {} # 与父表关联的外键字段名称以及值<dict> eg:{'foreign_key': foreign_key_value}
  12. __is_having_index = False # 是否需要添加序号<boolean>
  13. __batch_count = 0 # 分小批次插入时,每次插入的条数
  14. __is_returnable = False # 是否有返回值
  15. def __init__(self, env, insert_model_name, insert_values, insert_model_fields=None, insert_values_keys=None,
  16. foreign_key_field_dict=None, is_having_index=False, batch_count=0, is_returnable=False):
  17. self.__env = env
  18. self.__cr = env.cr
  19. self.__insert_model_name = insert_model_name
  20. self.__insert_values = insert_values
  21. self._init_insert_model_fields(insert_model_fields, insert_values)
  22. self.__insert_values_keys = insert_values_keys if insert_values_keys else self.__insert_model_fields
  23. self.__foreign_key_field_dict = foreign_key_field_dict
  24. self.__is_having_index = is_having_index
  25. self.__batch_count = batch_count
  26. self.__is_returnable = is_returnable
  27. def _init_insert_model_fields(self, insert_model_fields, insert_values):
  28. if insert_model_fields:
  29. self.__insert_model_fields = insert_model_fields
  30. else:
  31. if insert_values:
  32. self.__insert_model_fields = [key for key in insert_values[0]]
  33. def batch_insert(self):
  34. """
  35. 初始化后, 供外部调用的 批次插入的方法
  36. :return:
  37. """
  38. ids = []
  39. self.__append_other_fields()
  40. if not self.__batch_count or self.__batch_count > len(self.__insert_values):
  41. data_sql = self.__get_data_sql()
  42. ids = self.__batch_insert_data(data_sql)
  43. else:
  44. batch_values_list = self.__get_batch_values_list()
  45. for values in batch_values_list:
  46. self.__insert_values = values
  47. data_sql = self.__get_data_sql()
  48. ids.extend(self.__batch_insert_data(data_sql))
  49. if self.__is_returnable:
  50. result = self.__env[self.__insert_model_name].search([('id', 'in', ids)]) if ids else []
  51. return result
  52. def __append_other_fields(self):
  53. """
  54. 用于添加其他字段,例如 外键字段、序号等等,有待扩展 #TODO
  55. :return:
  56. """
  57. if self.__foreign_key_field_dict:
  58. for key in self.__foreign_key_field_dict:
  59. self.__insert_model_fields.append(key)
  60. self.__insert_values_keys.append(key)
  61. for dic in self.__insert_values:
  62. dic[key] = self.__foreign_key_field_dict[key]
  63. if self.__is_having_index:
  64. self.__insert_model_fields.append('show_index')
  65. self.__insert_values_keys('show_index')
  66. temp_num = 1
  67. for value in self.__insert_values:
  68. value['show_index'] = temp_num
  69. temp_num += 1
  70. def __get_data_sql(self):
  71. """
  72. 获取 类似 '(xxx,xxx,xxx),(xxx,xxx,xxx)' 的字符串
  73. """
  74. insert_values = self.__insert_values
  75. insert_values_keys = self.__insert_values_keys
  76. string_data = []
  77. for dic in insert_values:
  78. value_list = []
  79. for key in insert_values_keys:
  80. value = dic[key]
  81. if isinstance(value, tuple): # many2one类型处理
  82. value_list.append(value[0])
  83. elif isinstance(value, str):
  84. value_list.append("'{}'".format(value))
  85. elif isinstance(value, date):
  86. value_list.append("'{}'".format(value.strftime('%Y-%m-%d')))
  87. elif isinstance(value, datetime):
  88. value_list.append("'{}'".format(value.strftime('%Y-%m-%d %H:%M:%S')))
  89. elif not dic[key]: # 字段为空处理
  90. value_list.append('null')
  91. # TODO 应该还存在其他类型,有待扩展
  92. else:
  93. value_list.append(dic[key])
  94. string_data.append('({})'.format(','.join([str(value) for value in value_list])))
  95. data_sql = ','.join(string_data)
  96. return data_sql
  97. def __batch_insert_data(self, data_sql):
  98. """
  99. 批次插入方法
  100. """
  101. insert_fields = self.__insert_model_fields
  102. if not insert_fields:
  103. return
  104. insert_model_name = self.__insert_model_name
  105. return_sql = 'returning id' if self.__is_returnable else ''
  106. table_name = insert_model_name.replace('.', '_')
  107. sql = '''
  108. insert into
  109. {table_name}
  110. {fields}
  111. values
  112. {data_sql}
  113. {return_sql}
  114. '''.format(table_name=table_name, fields='({})'.format(','.join(insert_fields)), data_sql=data_sql,
  115. return_sql=return_sql)
  116. self.__cr.execute(sql)
  117. result = [value['id'] for value in self.__cr.dictfetchall()] if self.__is_returnable else []
  118. self.__env.clear() # 清除缓存
  119. return result
  120. def __get_batch_values_list(self):
  121. """
  122. 分批插入时, 获取 分批后的 values 的list 集合
  123. :return: <list<list<dict>>>
  124. """
  125. batch_count = self.__batch_count
  126. insert_values = self.__insert_values
  127. result = []
  128. count = 0
  129. while True:
  130. result.append(insert_values[count:count + batch_count])
  131. count += batch_count
  132. if count + batch_count > len(insert_values):
  133. if insert_values[count:]:
  134. result.append(insert_values[count:])
  135. break
  136. return result