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 ()