Einen Weg kenne ich schon - nur ist der sehr mühsam zu erkunden:
Du kannst alles in Qgis mit pyqgis machen, wenn du den Einstieg findest. Ist Python für Qgis.
Wie ich schon bei meinen Administrativen Grenzen bemerkte, ist die API-Doku grauenhaft und an Beispielen fehlt es auch massig. Aber gehen tut es 
Gruss
walter
ps: nur mal zur Abschreckung Ermunterung. So erzeuge ich regelmäßig meinen “Missing Countries Map”:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtGui
import processing, sys, time, psycopg2
import pprint
#Define our connection string
conn_string = "host='wno-server' dbname='planet2' user='osm'"
# print the connection string we will use to connect
#print "Connecting to database\n ->%s" % (conn_string)
# get a connection, if a connect cannot be made an exception will be raised here
conn = psycopg2.connect(conn_string)
# conn.cursor will return a cursor object, you can use this cursor to perform queries
cursor = conn.cursor()
#print "Connected!\n"
# execute our Query
cursor.execute("select * from osmstate " +
"where line like 'timestamp=%' " +
"order by lfn desc limit 1")
# retrieve the records from the database
record = cursor.fetchone()
# print out the records using pretty print
#pprint.pprint(record)
ts = record[2][10:]
print ts
uri = QgsDataSourceURI()
uri.setConnection("wno-server", "5432", "planet2", "osm", "")
uri.setDataSource("public", "planet_osm_polygon", "way",
"boundary='administrative' and osm_id<0 and admin_level = '2'","osm_id")
pgLayer = QgsVectorLayer(uri.uri(), "Countries2", "postgres")
if not pgLayer.isValid():
print "Layer countries failed to load!"
pgRenderer = pgLayer.rendererV2()
symbols = pgRenderer.symbols()
symbol = symbols[0]
symbol.setColor(QtGui.QColor.fromRgb(0,0,255))
QgsMapLayerRegistry.instance().addMapLayer(pgLayer)
clipLayer = QgsVectorLayer("/data/osm/qgis/shapes/coastline.shp", "Missing Countries", "ogr")
if not clipLayer.isValid():
print "Clipping Layer failed to load!"
clipRenderer = clipLayer.rendererV2()
clipRenderer.symbols()[0].setColor(QtGui.QColor.fromRgb(255,0,0))
QgsMapLayerRegistry.instance().addMapLayer(clipLayer)
processing.runalg('qgis:clip', pgLayer, clipLayer, "/tmp/missing_countries")
missingLayer = QgsVectorLayer("/tmp/missing_countries.shp", "Countries", "ogr")
if not missingLayer.isValid():
print "missingLayer failed to load!"
missingRenderer = missingLayer.rendererV2()
missingRenderer.symbols()[0].setColor(QtGui.QColor.fromRgb(241,244,199))
QgsMapLayerRegistry.instance().addMapLayer(missingLayer)
pgId = pgLayer.id();
QgsMapLayerRegistry.instance().removeMapLayer(pgId)
################### Create Graph #####################
mapRenderer = iface.mapCanvas().mapRenderer()
layers = [missingLayer.id(),clipLayer.id()]
mapRenderer.setLayerSet(layers)
c = QgsComposition(mapRenderer)
c.setPlotStyle(QgsComposition.Print)
c.setPaperSize(148,90)
c.setPrintResolution(300)
# add map
x, y = 0, 0
w, h = c.paperWidth(), c.paperHeight()
composerMap = QgsComposerMap(c, x,y,w,h)
c.addItem(composerMap)
#output to image
dpi = c.printResolution()
dpmm = dpi / 25.4
width = int(dpmm * c.paperWidth())
height = int(dpmm * c.paperHeight())
BackgroundColor = QColor(0,0,255)
# create output image and initialize it
image = QImage(QSize(width, height), QImage.Format_ARGB32)
image.setDotsPerMeterX(dpmm * 1000)
image.setDotsPerMeterY(dpmm * 1000)
image.fill(BackgroundColor)
header = QgsComposerLabel(c)
header.setItemPosition(40,1)
header.setBackgroundEnabled(0)
newFont = QFont("Comic Sans MS", 18)
header.setFont(newFont)
header.setText("Missing Countries Map")
header.adjustSizeToText()
c.addItem(header)
header2 = QgsComposerLabel(c)
header2.setItemPosition(50,11)
header2.setBackgroundEnabled(0)
newFont2 = QFont("Comic Sans MS", 10)
header2.setFont(newFont2)
header2.setText("TS="+ts)
header2.adjustSizeToText()
c.addItem(header2)
footer = QgsComposerLabel(c)
footer.setItemPosition(124,87.5)
footer.setBackgroundEnabled(0)
newFont3 = QFont("Times Roman", 4)
footer.setFont(newFont3)
footer.setText(time.ctime())
footer.adjustSizeToText()
c.addItem(footer)
legend = QgsComposerLegend(c)
legend.model().setLayerSet(mapRenderer.layerSet())
legend.setItemPosition(5,65)
legend.setFrameEnabled(1)
newFont = QFont("Comic Sans MS", 6)
legend.setStyleFont(QgsComposerLegendStyle.Title, newFont)
legend.setStyleFont(QgsComposerLegendStyle.Subgroup, newFont)
legend.setStyleFont(QgsComposerLegendStyle.SymbolLabel, newFont)
legend.setStyleMargin(QgsComposerLegendStyle.Title,2)
legend.setTitle("Legend")
legend.setSymbolHeight(2)
legend.adjustBoxSize()
c.addItem(legend)
# render the composition
imagePainter = QPainter(image)
imagePainter.setRenderHint(QPainter.Antialiasing)
sourceArea = QRectF(0, 0, c.paperWidth(), c.paperHeight())
targetArea = QRectF(0, 0, width, height)
c.render(imagePainter, targetArea, sourceArea)
imagePainter.end()
imageFile = "/data/osm/maven/DataServer/data/osm/forum/admin/qgis/Q_World_Gaps_"+ts+".png"
print "saving to "+imageFile
image.save(imageFile)
ergibt z.B.

ach ja: der Postgresql-User OSM hat natürlich nur RO-Rechte auf einige Tabellen 