1

I'm using QGIS 3.10.1. I've created virtual layers from an ODBC data source and using the (relatively) new feature "label editing". I was able to show/hide/move labels of a layer. But just after saving and refreshing/reloading the layer all 'auxiliary_storage_' labeling attribute values are gone. The same happens if I restart the QGIS project. Saving the project as qgz (compressed, including QGD) doesn't provide any remedy.

The workaround would be to add a custom Python action for/at the virtual layer scope, pointing to an expression like this (it will temporarily re-populate all stored feature attributes from the joined, in-memory auxiliary layer to the target, non-editable vector layer), credits go to @Detlev:


# -*- coding: utf-8 -*-

from qgis.core import *
from qgis.gui import *
from qgis.utils import *

@qgsfunction(args='auto', group='My')
def update_aux(feature, parent, context):
    """
    Updates the auxiliary layer's attributes (if any) of the selected layer
    <h2>Example usage:</h2>
    <ul>
        <li>update_aux()</li>
    </ul>
    """
    layer = QgsProject.instance().mapLayer(context.variable("layer_id"))
    auxiliaryLayer = layer.auxiliaryLayer()
    if auxiliaryLayer is not None:
        joinField = auxiliaryLayer.joinInfo().joinFieldName()
        joinKey = auxiliaryLayer.joinInfo().targetFieldName()
        QgsMessageLog.logMessage("Updating auxiliary layer({}) values, join:  ({}->{})".format(auxiliaryLayer.id(), joinField, joinKey), "My", level=Qgis.Info)
        fnm = auxiliaryLayer.dataProvider().fieldNameMap()
        fim = {index: name for name, index in fnm.items()}
        for auxiliaryFeature in auxiliaryLayer.getFeatures():
            filterExpression = "{} = {}".format(joinKey, auxiliaryFeature[joinField])
            featureRequest = QgsFeatureRequest().setFilterExpression(filterExpression)
            layerFeature = QgsFeature()
            layer.getFeatures(featureRequest).nextFeature(layerFeature)
            if layerFeature is not None:
                for i in fim:
                    propertyDefinition = auxiliaryLayer.propertyDefinitionFromIndex(i)
                    auxiliaryFieldName = QgsAuxiliaryLayer.nameFromProperty(propertyDefinition, True)
                    auxiliaryFieldIndex = layer.fields().indexFromName(auxiliaryFieldName)
                    if auxiliaryFieldIndex >= 0:
                        QgsMessageLog.logMessage("changeAttributeValue({}, {}, {})".format(layerFeature.id(), auxiliaryFieldIndex, auxiliaryFeature[i]), "My", level=Qgis.Info)
                        layer.changeAttributeValue(layerFeature.id(), auxiliaryFieldIndex, auxiliaryFeature[i])
            else:
                QgsMessageLog.logMessage("Couldn't find a feature with {} in the current layer!".format(featureRequest.filterExpression()), "My", level=Qgis.Info)
        if iface.mapCanvas().isCachingEnabled():
            layer.triggerRepaint()
        else:
            iface.mapCanvas().refresh()
    else:
        QgsMessageLog.logMessage("There is no auxiliary layer!", "My", level=Qgis.Warning)


Does somebody have an idea, what's going wrong here? I've spent countless hours formatting the labels using the rule-based engine for printing, it doesn't seem to be a proper solution for map production.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.