Simple Objects in Data Tables

Hi everyone!

I feel quite silly but I’m a bit stumped and the behaviour of Anvil is confusing me…which experience has almost always shown to be my error!

I have two main types of Simple Objects in several of my Data Tables:

Nested Dictionaries and Lists of Dictionaries.

I love using them because I can quickly get lots of data client-side, it presents instantaneously, and (Mostly) is very easy to work with.

But on SOME occasions when I try update them in the data table, nothing gets updated.

So my code client side looks like:

def button_click(self,**event_args):
  anvil.server.call('update_data',key='name',val=self.text_box_1.text)

Server Side

@anvil.server.callable
def update_data(key,val):
  my_data = app_tables.clients.get(client_id='fra_001')['contractor_data']
  # this is a list of dictionaries
  for cont in my_data:
    if cont['change']:
      cont[key] = val
  app_tables.clients.get(client_id='fra_001')['contractor_data'] = my_data

I’ve also tried:

@anvil.server.callable
def update_data(key,val):
  my_data = app_tables.clients.get(client_id='fra_001')['contractor_data']
  # this is a list of dictionaries
  for cont in my_data:
    if cont['change']:
      del cont[key]
      cont[key] = val
      # believe it or not this is the only method that works sometimes!
  app_tables.clients.get(client_id='fra_001')['contractor_data'] = my_data

and…

@anvil.server.callable
def update_data(key,val):
  my_row = app_tables.clients.get(client_id='fra_001')
  my_data = my_row['contractor_data']
  # this is a list of dictionaries
  for cont in my_data:
    if cont['change']:
      cont[key] = val
  my_row.update(contractor_data=my_data)

Sometimes some of the above work. Sometimes only one of them does. Sometimes none.
What am I missing?! I’m sure I’m missing an elegant way to once and for all handle the updating of simple objects in data tables!

Thanks in advance!

Bruce

The problem here is that you’re not changing the dict that you think you are…

In your for loop, you ‘create’ the variable cont which is a dict ‘extracted’ from my_data.

Crucially, at that point, cont is a separate dict in its own right which means that, when you update it, there is no effect on my_data.

Instead, you’ll need to build your new list of dicts and pass that to the app tables update.

Aha! Thanks I’ll let you know how it goes tomorrow…

Just Like Owen said, here is exactly how I would do what you are asking, with some sparse annotation:

Wow thanks!

If I understand what you’ve written, enumerate actually works on the original dictionary and doesn’t just extract it to another one as my normal for loop did?

And one extra follow-up (always hit that reply button too early):

How would you do it with a nested dictionary?

Example if contractor_data was:

{“id001”:{key:val,key2:val2},” id002”:{key:val,key2:val2},…etc}?

You were looping through a list (that has indexes) that contained multiple dictionaries.

enumerate just allows you to loop through both the item in the list and capture the number of the index at the same time.

We are not working on the original dictionary, like @owen.campbell pointed out above, but instead we update the list with a new value if it needs to be updated, and then we update the entire row (just that one column really) with a new list if that has changed.

So you still end up operating on a copy, but then you check the ‘real’ one against it and change the ‘real’ one if the copy ends up being different that what you started with.

in python > 3.5 when you iterate over a dictionary with a for loop you end up with the keys, so something like:

so like in other languages:

contractor_data[contractor_data_key][key2] = new_val2

would be how you update a value in something nested.

off topic, but python can be more explicit (for legibility) and this also works:

contractor_data[contractor_data_key].update( { key2: new_val2 } )

With the above you can update multiple entries at once by making that update dictionary any arbitrary length of keys and data. Duplicate keys will overwrite, and new ones will be created.

1 Like