4

I wish to create a field which automatically updates with the current timestamp when edits are made to a feature.

I am using QGIS 3.4 and I am testing this using a shapefile.

Following @Joseph's answer for this question I tried updating his script to work in QGIS 3.4 as per his instructions (if I followed them correctly, not guaranteed!) to this:

layer = qgis.utils.iface.activeLayer()

def update():
    field = layer.fields().lookupField('fieldName')
    e = QgsExpression( " $now " )
    e.prepare( layer.pendingFields() )
    for feat in layer.selectedFeatures():
        feat[field] = e.evaluate( feat )
        layer.updateFeature( feat )

layer.attributeValueChanged.connect(update)

However this returns the following error:

2018-11-29T11:13:00     WARNING    Traceback (most recent call last):
              File "", line 4, in update
             AttributeError: 'QgsVectorLayer' object has no attribute 'pendingFields'

What's wrong here?

Also will this work on geometry edits or only with attribute edits?

Will this also work for a SpatiaLite layer?

3 Answers 3

4

Replace pendingFields() by fields() should do the trick for your error. You may still have errors running your code in QGIS 3.X because there is no backward compatibility. You have to fix all API changes and it will works.

the pendingFields() methods has been removed in QGIS 3.X API and replaced by fields().

Also will this work on geometry edits or only with attribute edits?

To listen to geometry changes, you can connect to geometryChanged signal

Full code will be:

layer = qgis.utils.iface.activeLayer()

def update():
    field = layer.fields().lookupField('fieldName')
    e = QgsExpression( " $now " )
    for feat in layer.selectedFeatures():
        feat[field] = e.evaluate()
        layer.updateFeature( feat )

layer.attributeValueChanged.connect(update)
layer.geometryChanged.connect(update)

Will this also work for a SpatiaLite layer?

This would probably also works on SpatiaLite layers.

9
  • 1
    Your code works if you remove e.prepare( layer.fields() ) and change feat[field] = e.evaluate( feat ) to feat[field] = e.evaluate()
    – Joseph
    Nov 29, 2018 at 11:43
  • Now when I make an edit QGIS crashes haha. Damnit. I'll keep trying. Thanks guys Nov 29, 2018 at 11:54
  • @Joseph , YoLecomte - Which versions of QGIS are ye using? I'm on 3.4.0 and it crashes when I make an edit with that script running. Nov 29, 2018 at 12:22
  • I doesn't test it for now. Will make a try later. No time for the moment...
    – YoLecomte
    Nov 29, 2018 at 12:24
  • 2
    @TeddyTedTed - Also on 3.4.0 for Win7 64-bit. It works for me from the Python Console. Note that the layer needs to be editable and the field type correct (e.g. string-type) in order for the datestamp to be written successfully. This works on spatialite layers too.
    – Joseph
    Nov 29, 2018 at 12:31
3

Create a new date or datetime field.

Go to the layer properties › Attributes Form. Select your field.

Activate the checkbox Apply default value on update and set the Default value to $now.

Screenshot of Attributes Form dialog

0

I also need a decent fix but I managed a dirty fix.

I cannot stop the value from updating every time any attribute in the record or the geometry is edited. But, I can make a sort of "lock" on the value.

This is to capture the date the feature is physically inspected on site. In some cases, the date of survey might be the only thing entered by the user.

I set 2 checkbox fields called "SurveyedYN" and "confirm". The datetime field is called "SurveyDate" and will update to the current time if the SurveyYN is ticked AND the confirm is unticked. If both are ticked, or both are unticked, the datetime will update to its current value.

It looks like this in the default value box for SurveyDate with "apply on update" switched on:

If ("SurveyedYN" = 'Y' AND "confirm" = 'N', $now(), "SurveyDate")

In the data entry form, the sequence of inputs forces the user to tick SurveyedYN first, then confirmed second, so the logic only works if the user does not mess up the order.

It would also work with a single checkbox if you know the edits you make will be committed before the box has to be ticked.

Not great but functional

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.