Writing Back to a DB row not working

I’m trying to update a single row in the database using “write-back”.

I have sensors sending temps back to an anvil API, then into the DB. Also setup users, so for now I’m using the logged in user to query the sensor/setup data.

THE UI

The form code

class Setup(SetupTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Any code you write here will run when the form opens.
    #make db call to get setup data. allowing writing and up dating to the db
    #get the logged in user first
    self.getSensorData()
  
  
  def getSensorData(self, **event_args):
      print(f"This user has logged in: {anvil.users.get_user()['email']}")
      logged_in_user = anvil.users.get_user()['email']
      getSetupRow = anvil.server.call('getSensorSetupData', logged_in_user)
      self.room_name_text_box.text = getSetupRow['sensorname']
      self.desired_humidity_text_box.text = getSetupRow['targetedhumidity']
      self.desired_temp_text_box.text = getSetupRow['targetedtemp']
      self.light_type_dropdown.selected_value = getSetupRow['lightType']
      self.leaf_temp_offset_text_box.text = getSetupRow['leafoffset']

This is the query I have for now.


@anvil.server.callable
def getSensorSetupData(EMAIL):
  logged_in = EMAIL
  get_sensor_from_user = app_tables.setup.get(sensorOwner=EMAIL)
  if get_sensor_from_user:
    print("Sensor Found")
    print(get_sensor_from_user['sensorid'])
  return get_sensor_from_user

I’m trying to allow the user to update the textboxes and have it save then they click off or press enter OR ideally with the save button is clicked.

I have the data binding set to the following:

And this is what the DB looks like.

What am I missing? I’m setting the self.item[‘sensorname’] write back to match the table name in the database. It pulls info ok, but doesnt save/write-back.

Your forms don’t have permission to write to the table. Look in your db table at the Permissions section. Forms are currently set to no access.

Note that using write back is not secure at all. It might be fine for some applications, but for more security you want to call a server function to save to the data table.

I didnt think about the form not having permissions. Thats easy.

Will definitely rethink how its setup and look at implementing a server method instead of write back.

Weird. I allowed the form to write to db and it doesnt save anything. I know before when I had the issue about permissions it would give me an error.

For some reason it doesnt seem to fire anything or give any CLI output when I enter something into the textbox to write back.

May just go ahead and write a server function with the “SAVE” button and see if it will update the field that way.

The “writeback” checkbox is for writing the value back from the form to the named variable. What you do with the resulting variable is up to you, i.e., to your code. Anvil has no way of knowing which of a thousand things you might want to do with the value after that.

Can you share a clone-link?

Right now, it looks like you are making an assignment to the text property in getSensorData. That’s not how data-bindings work: They bind the attribute to a python reference, and the assignments you are making (i.e. self.room_name_text_box.text = row['sensorname']) are just that: One-way simple assignments of a string to the attribute self.room_name_text_box.text.

So, to use bindings, you have to assign to self.item and refernece that (your reference in the binding looks correct). So simply replacing your function with:

  def getSensorData(self, **event_args):
      print(f"This user has logged in: {anvil.users.get_user()['email']}")
      logged_in_user = anvil.users.get_user()['email']
      getSetupRow = anvil.server.call('getSensorSetupData', logged_in_user)
      self.item = getSetupRow
      # and bind all your component attributes to keys in self.item

Should just work.

Worth noting that self.item is kind of special, but it’s not magic - you still need to tell Anvil what self.item references. (This often happens for you in repeating panels and such.)

Edit (for completeness):
Actually (in the case of repeating panels) it’s just that the assignment to self.item is occuring in that init_components call. Note that in that case you can get the item earlier from properties["item"], so I’m assuming that all that’s happening in the init_components call is self.item=properties['item']!

This logic is exactly what I didnt understand.

– So, to use bindings, you have to assign to self.item and refernece that (your reference in the binding looks correct). So simply replacing your function with

This is what I was wanting to accomplish but wasnt sure how to connect the self.item.

the self.item = getSetupRow is what I was missing.

I decided to just write a server module and pass the data back to it, then have it do the deleting.

This project is for esp32 temp sensors in our greenhouses and I’m using the anvil API to POST the data back to the app.