postgisupdate.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. # -*- coding: utf-8 -*-
  2. """
  3. ***************************************************************************
  4. postgisupdate.py
  5. ---------------------
  6. Date : November 2012
  7. Copyright : (C) 2012 by Victor Olaya
  8. Email : volayaf at gmail dot com
  9. ***************************************************************************
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. ***************************************************************************
  17. """
  18. __author__ = 'wanger'
  19. __date__ = 'November 2024'
  20. __copyright__ = '(C) 2024, wanger'
  21. import os
  22. from osgeo import ogr, gdal
  23. from PyQt5.QtGui import QIcon
  24. from PyQt5.QtWidgets import QApplication
  25. from future.moves import sys
  26. from qgis.PyQt import QtWidgets
  27. from qgis.core import (QgsProcessing,
  28. QgsProcessingParameterFeatureSource,
  29. QgsProcessingParameterString,
  30. QgsProcessingParameterFile,
  31. QgsProcessingParameterDateTime,
  32. QgsProcessingParameterEnum,
  33. QgsProcessingParameterCrs,
  34. QgsProcessingParameterField,
  35. QgsProcessingParameterExtent,
  36. QgsProcessingParameterBoolean,
  37. QgsProcessingParameterProviderConnection,
  38. QgsProcessingParameterDatabaseSchema,
  39. QgsProcessingParameterDatabaseTable,
  40. QgsProviderRegistry,
  41. QgsProcessingException,
  42. QgsProcessingParameterDefinition,
  43. QgsProviderConnectionException,
  44. QgsDataSourceUri)
  45. from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
  46. from processing.algs.gdal.GdalUtils import GdalUtils
  47. from processing.tools.PrintUtils import printStr
  48. from processing.tools.StringUtils import (getConnectionStr, getNow)
  49. from processing.tools.GeoServer.Geoserver import Geoserver
  50. from processing.tools.PostgreSQL.PostgreSQL import PostgreSQL
  51. from processing.tools.system import isWindows
  52. pluginPath = os.path.normpath(os.path.join(
  53. os.path.split(os.path.dirname(__file__))[0], os.pardir))
  54. gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
  55. gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
  56. class Postgisupdate(GdalAlgorithm):
  57. LOGIN_USER = "admin"
  58. UPDATEFILE = 'UPDATEFILE'
  59. TARGET = 'TARGET'
  60. ALLOWOVERLAP = "ALLOWOVERLAP"
  61. DATABASE = 'DATABASE'
  62. INPUTFILE = 'INPUTFILE'
  63. SCHEMA = 'SCHEMA'
  64. TABLE = 'TABLE'
  65. HOST = 'HOST'
  66. DBNAME = 'DBNAME'
  67. PORT = 'PORT'
  68. USER = 'USER'
  69. PASSWORD = 'PASSWORD'
  70. selectedValue = "selectedValue"
  71. tables = []
  72. checklogs = []
  73. def __init__(self):
  74. super().__init__()
  75. def initAlgorithm(self, config=None):
  76. self.addParameter(QgsProcessingParameterFeatureSource(self.UPDATEFILE,
  77. self.tr('更新数据包'),
  78. types=[QgsProcessing.TypeVector]))
  79. pgconn = PostgreSQL(schema='base')
  80. self.tables = pgconn.getManagerTables(username=self.LOGIN_USER)
  81. pgconn.close()
  82. tablenames = []
  83. for row in self.tables:
  84. tablenames.append(row[2])
  85. self.addParameter(QgsProcessingParameterEnum(name=self.TARGET,
  86. description=self.tr('目标数据源'),
  87. options=tablenames))
  88. self.addParameter(QgsProcessingParameterBoolean(self.ALLOWOVERLAP,
  89. self.tr('是否允许更新重叠数据'),
  90. defaultValue=False))
  91. def name(self):
  92. return 'postgisupdate'
  93. def icon(self):
  94. return QIcon(os.path.join(pluginPath, 'images', 'dbms', 'update.png'))
  95. def displayName(self):
  96. return self.tr('数据更新')
  97. def shortDescription(self):
  98. return self.tr('更新数据库目标')
  99. def tags(self):
  100. t = self.tr('import,into,postgis,database,vector').split(',')
  101. t.extend(super().tags())
  102. return t
  103. def group(self):
  104. return self.tr('数据更新维护')
  105. def groupId(self):
  106. return 'updatedata'
  107. def setSelectedValue(self, v):
  108. printStr(v)
  109. self.selectedValue = v
  110. def getSelectedValue(self):
  111. return self.selectedValue
  112. def updateVector(self, parameters, context, feedback, executing=True):
  113. print("增量更新开始啦")
  114. print("===========进行数据更新开始===========")
  115. #当前时间
  116. now = getNow()
  117. ogrLayer, layername = self.getOgrCompatibleSource(self.UPDATEFILE, parameters, context, feedback, executing)
  118. print(ogrLayer)
  119. allowoverlap = self.parameterAsBoolean(parameters, self.ALLOWOVERLAP, context)
  120. tableinfo = self.tables[parameters[self.TARGET]]
  121. tablename = tableinfo[1]
  122. ywlx = tableinfo[3]
  123. pgconn = PostgreSQL(schema='base')
  124. print("===========备份表===========")
  125. # pgconn.resetBackTable(tablename=tablename)
  126. srid = pgconn.getVectorTableSrid(tablename=tablename)
  127. geomtype = pgconn.getVectorTableGeomType(tablename=tablename)
  128. print("===========打开矢量数据===========")
  129. ds = ogr.Open(ogrLayer, 0)
  130. layer = ds.GetLayer()
  131. layer_spatial_ref = layer.GetSpatialRef()
  132. layer_def = layer.GetLayerDefn()
  133. vectorepsg = layer_spatial_ref.GetAttrValue('AUTHORITY', 1)
  134. alltablefiled = pgconn.getAllTableField(tablename=tablename)
  135. insertcount = 0
  136. misscount = 0
  137. for feature in layer:
  138. geom_wkt = feature.GetGeometryRef().ExportToWkt()
  139. # 判断是否允许更新重叠数据
  140. updatebool = True
  141. if allowoverlap == False:
  142. instersectsCount = pgconn.getInstersectsCount(tablename=tablename, tablesrid=srid, wkts=[geom_wkt],
  143. wktsrid=vectorepsg)
  144. count = int(instersectsCount)
  145. if count > 0:
  146. updatebool = False
  147. misscount += 1
  148. if updatebool == True:
  149. # 遍历当前数据的属性信息
  150. attributes = {}
  151. for i in range(layer_def.GetFieldCount()):
  152. field_def = layer_def.GetFieldDefn(i)
  153. field_name = field_def.GetName()
  154. field_value = feature.GetField(i)
  155. attributes[field_name] = field_value
  156. # print(field_value)
  157. # if self.is_string(field_value) == True:
  158. # print(field_value.encode('utf-8'))
  159. # 拼接insert into语句
  160. insertvalus = []
  161. for field in alltablefiled:
  162. b = self.contains_keys(attributes, [field.lower()])
  163. if b == True:
  164. insertvalus.append(attributes[field.lower()])
  165. else:
  166. b = self.contains_keys(attributes, [field.upper()])
  167. if b == True:
  168. insertvalus.append(attributes[field.upper()])
  169. else:
  170. insertvalus.append(None)
  171. pgconn.insertVectorFeature(tablename=tablename, fields=alltablefiled, values=insertvalus, wkt=geom_wkt,
  172. wktsrid=vectorepsg, geomtype=geomtype, rksj=now)
  173. insertcount += 1
  174. pgconn.updateVectorVersion(tablename=tablename, version=now)
  175. pgconn.close()
  176. return {
  177. "状态": "更新成功",
  178. "插入": str(insertcount) + "条记录",
  179. "忽略": str(misscount) + "条记录,存在空间叠加。"
  180. }
  181. # 判断数据是否为字符串
  182. def is_string(self, var):
  183. return isinstance(var, str)
  184. def getConsoleCommands(self, parameters, context, feedback, executing=True):
  185. self.checklogs = []
  186. ogrLayer, layername = self.getOgrCompatibleSource(self.UPDATEFILE, parameters, context, feedback, executing)
  187. print(ogrLayer)
  188. allowoverlap = self.parameterAsBoolean(parameters, self.ALLOWOVERLAP, context)
  189. print("===========进行数据检查开始===========")
  190. print("===========获取选择的数据库表===========")
  191. tableinfo = self.tables[parameters[self.TARGET]]
  192. tablename = tableinfo[1]
  193. ywlx = tableinfo[3]
  194. pgconn = PostgreSQL(schema='base')
  195. srid = pgconn.getVectorTableSrid(tablename=tablename)
  196. print("===========打开矢量数据===========")
  197. ds = ogr.Open(ogrLayer, 0)
  198. layer = ds.GetLayer()
  199. layer_spatial_ref = layer.GetSpatialRef()
  200. print("===========坐标系检查===========")
  201. vectorepsg = layer_spatial_ref.GetAttrValue('AUTHORITY', 1)
  202. # 坐标系不一致
  203. if vectorepsg != str(srid):
  204. self.checklogs.append(f"与目标数据坐标系不一致,请先重投影到EPSG:{srid}!")
  205. print("===========必要字段检查===========")
  206. layer_def = layer.GetLayerDefn()
  207. vectorfields = []
  208. for i in range(layer_def.GetFieldCount()):
  209. field_def = layer_def.GetFieldDefn(i)
  210. vectorfields.append(field_def.GetName().lower())
  211. requirefields = pgconn.getMustRequireField(tablename=tablename, ywlx=ywlx)
  212. missfields = []
  213. for requirefield in requirefields:
  214. contain = False
  215. for vectorfield in vectorfields:
  216. if vectorfield == requirefield:
  217. contain = True
  218. break
  219. if contain == False:
  220. missfields.append(requirefield)
  221. if len(missfields) > 0:
  222. miss = ','.join(missfields)
  223. self.checklogs.append(f'更新包中{miss}字段不存在,请先检查并修复再进行更新!')
  224. print("===========空间叠加检查===========")
  225. # geom_wkt = []
  226. # for feature in layer:
  227. # geom_wkt.append(feature.GetGeometryRef().ExportToWkt())
  228. # instersectsCount = pgconn.getInstersectsCount(tablename=tablename, tablesrid=srid, wkts=geom_wkt,
  229. # wktsrid=vectorepsg)
  230. # count = int(instersectsCount)
  231. # if allowoverlap == False and count > 0:
  232. # self.checklogs.append(f"更新包与目标数据有{instersectsCount}块图斑空间重叠!")
  233. pgconn.close()
  234. return self.checklogs
  235. def contains_keys(self, obj, keys):
  236. if isinstance(obj, dict):
  237. return all(key in obj.keys() for key in keys)
  238. elif hasattr(type(obj), '__dict__'):
  239. return all(key in obj.__dict__ for key in keys)
  240. else:
  241. raise ValueError("Invalid object type")
  242. def commandName(self):
  243. return "ogr2ogr"