I have no problem using the DB Manager in QGIS 2.18, but if I try to add a layer based on a long running query (1 min+), QGIS becomes entirely unusable. It would appear that every map pan, every mouse click, etc., is triggering some kind of layer refresh.
This seems silly for one, especially given that you can right click the layer and request a refresh. And more important, it makes the application unusable. What am I doing wrong here? Is it not possible to create the layer and only have it update when requested?
Obviously I can create materialized views in postgres for all the spatial queries, but that seems to defeat the point of being able to do it in QGIS
Unfortunately the repaintRequested() signal is not triggered refreshing the canvas so I write a little python function that you can paste in QGIS python console editor to generate a materialized view from a query and add to mapcanvas as layer on the fly adding an action to legend menu for refreshing and reloading the view on demand
from qgis.core import QgsVectorLayer, QgsDataSourceURI, QgsMapLayerRegistry
from PyQt4.QtSql import QSqlDatabase
from PyQt4.QtGui import QAction
PSQLHost = "your_db_host"
PSQLPort = 5432
PSQLDatabase = "your_db"
PSQLUsername = "your_db_user"
PSQLPassword = "your_db_password"
LAYERNAME = "my materialized_view_layer"
QUERY = "select * from your_table"
class materialized_layer:
def __init__(self):
#setup connection
geom_field = "geom"
pkey_field = "id"
self.db = QSqlDatabase.addDatabase("QPSQL")
self.db.setHostName(PSQLHost)
self.db.setPort(PSQLPort)
self.db.setDatabaseName(PSQLDatabase)
self.db.setUserName(PSQLUsername)
self.db.setPassword(PSQLPassword)
self.db.open()
# generate materialized view
create_query = 'CREATE MATERIALIZED VIEW "%s" AS %s' % (LAYERNAME,QUERY)
self.db.exec_(create_query)
# add to canvas
qgis_uri = QgsDataSourceURI()
qgis_uri.setConnection(PSQLHost,str(PSQLPort),PSQLDatabase,PSQLUsername,PSQLPassword)
qgis_uri.setDataSource("",LAYERNAME,geom_field,"",pkey_field)
self.materialized_layer = QgsVectorLayer(qgis_uri.uri(), LAYERNAME, "postgres")
if self.materialized_layer.isValid():
#register new qgis layer and add action to layer contextual menu
QgsMapLayerRegistry.instance().addMapLayer(self.materialized_layer,True)
refresh_materialized_action = QAction( "Refresh materialized view and reload", iface.legendInterface() )
iface.legendInterface().addLegendLayerAction(refresh_materialized_action, "","", QgsMapLayer.VectorLayer,False)
iface.legendInterface().addLegendLayerActionForLayer(refresh_materialized_action, self.materialized_layer)
refresh_materialized_action.triggered.connect(self.refresh_layer)
else:
print "invalid layer"
def reload_layer(self):
print "RELOADING MATERIALIZED VIEW"
self.materialized_layer.reload()
def refresh_layer(self):
print "REFRESHING MATERIALIZED VIEW"
refresh_query = 'REFRESH MATERIALIZED VIEW "%s"' % LAYERNAME
self.db.exec_(refresh_query)
self.reload_layer()
l = materialized_layer ()
I wrote a plugin called postgisQueryBuilder that helps in db view creation, even with materialized, directive and allows, browsing the db connection available layers, to refresh the materialized views from QGIS. Check if you can be helpful.
来源:https://stackoverflow.com/questions/41176146/using-qgis-how-to-properly-link-a-postgis-sql-layer