How to turn a list of Row objects into a list of Dicts with the Row contents

I am trying to extract data from my data table on the server side to present in the following format:

[[{row contents}], [{row 2 contents}, {row 3 contents}] ... 

At the moment, I can get the format correct, but I get the row being returned, when I really want a dict with the row values returned:

[[<LiveObject: anvil.tables.Row>, <LiveObject: anvil.tables.Row>, <LiveObject: anvil.tables.Row>], [<LiveObject: anvil.tables.Row>]]
[[<LiveObject: anvil.tables.Row>, <LiveObject: anvil.tables.Row>, <LiveObject: anvil.tables.Row>], [<LiveObject: anvil.tables.Row>]]

Each of the anvil.tables.Row items above refers to a ā€œPushā€ that’s stored in the linked_pushes column - here’s the table Row I’ve searched for:

I’m using this code to extract the list above:

@anvil.server.callable
def get_push_global_pushes(my_project):
  ilist = [
    {
    'linked_pushes' : r['linked_pushes']
    }
    for r in app_tables.global_push.search(Project=my_project)
  ]
  irowlist = [d['linked_pushes'] for d in ilist]
  return irowlist

The output should be a list, where each row in the Global_Push table has an embedded list of ā€œlinked_pushesā€, and each of these is unpacked into a dict giving me the Push text and linked Interview ā€œinterviewee_nameā€ - see the Push table below:

And here’s the Interviews table:

I keep trying various convoluted methods to extract the information, but I’m tying myself in knots. Is there a straightforward way for me to iterate over the list output I’ve shared above, and turn each Row into a dict like this:

[[{Push : When I get a new job and... , Interview.interviewee_name : Dave}] 

Perhaps all you need is to convert this:
'linked_pushes' : r['linked_pushes']
Into this:
'linked_pushes' : dict(r['linked_pushes'])
?

1 Like

Thanks Stefano - this triggers the following error:

TypeError: unhashable type: 'list'

from this line of code:

for r in app_tables.global_push.search(Project=my_project)

Do you know of any comprehensive resources that I can read to understand how these searches work? I’ve seen a few questions on here where people are trying to do similar things, but nothing that’s exactly what I’m after (even though it seems like a relatively basic requirement).

I just need to unpack the linked objects into dicts in the same structure that the objects have been returned to me by the first function. For some reason my brain isn’t picking up how this works very well.

It sounds like you are using a list as a dictionary key.

And it sounds like you need to get more familiar with lists and dictionaries in python rather than Anvil searches.

1 Like

Yes, it’s all rather confusing to me. I had experience working with Ruby on Rails previously and searching for attributes of linked objects was straightforward.

I solved this issue, most likely NOT in the most elegant or Python-esque manner, but I’m adding it here to the forum in case others struggle and they can make sense of my code.

Note, if you’re new to Python I may not have used the correct names of the functions and elements in my code comments below, but the code does work

#pull a list of pushes that are linked to the global push and format them into a list of lists of dict elements for the ClusterPushes form
@anvil.server.callable
def get_push_global_pushes(my_project):
 #step through the global_push table and extract the linked_push text
  ilist = [
    {
    'linked_pushes' : r['linked_pushes']
    }
    for r in app_tables.global_push.search(Project=my_project)
  ]
  push_text_list = [d['linked_pushes'] for d in ilist]
  #first we set up an empty push_outcome list to put the results in
  push_outcome = []
  #then go through the lists inside push_text_list, 
  for p in push_text_list:
    #break out the row objects inside each list, ensuring we continue until each row in a list has been processed
    p_length = len(p)
    #whilst the list has content
    while p_length >0:
      #create a new placeholder list to store the row details
      push_l = []
      #pull out each row "l" and find both the Push and the Interview/interviewee_name
      for l in p:
        push=l['Push']
        #print(push)
        interview=l['Interview']
        interviewee=interview['interviewee_name']
        #build a dict for each of these rows to use in the front end
        push_d = {'Push' : push, 'Interviewee' : interviewee}
        #add each dict to the push_l list
        push_l.append(push_d)
        #when we get to the end of the rows, move the whole push_l list to the push_outcome list
        if p_length == 1:
          push_outcome.append(push_l)
        #make sure the while loop doesn't go on forever
        p_length -= 1
  return push_outcome
1 Like

There is nothing wrong with this code. You could make it slightly more pythonic by adding push_l to push_outcome before populating it, instead of using the if p_length == 1 test, and by getting rid of the p_length:

  push_outcome = []
  for p in push_text_list:
      push_l = []
      push_outcome.append(push_l)
      for l in p:
        push=l['Push']
        interview=l['Interview']
        interviewee=interview['interviewee_name']
        push_d = {'Push' : push, 'Interviewee' : interviewee}
        push_l.append(push_d)

Or using a list comprehension:

  push_outcome = []
  for p in push_text_list:
    push_outcome.append([
      {
        'Push' : l['Push'],
        'Interviewee' : l['Interview']['interviewee_name']
      }
      for l in p
    ])

All of this could be something like:

  push_outcome = [
    [
      {
        'Push' : l['Push'],
        'Interviewee' : l['Interview']['interviewee_name']
      }
      for l in p
    ]
    for p in push_text_list
  ]

And also the part above, where push_test_list is defined, could be included into the list comprehension to make a monster one liner where readability goes down the drain.

Using too many nested comprehensions often makes the code unreadable, so maybe getting rid of the p_length would be the right thing to do, but keeping the cycle as you have it.

… but I may have gotten it completely wrong, because I don’t know what’s in the data and I can’t test it.

2 Likes