Partially-writable Data Table rows

Here’s something neat I built for a customer who has a support plan – I thought I’d share it with the forum:

This developer wanted to be able to use Data Bindings to edit values in a Data Table row. However, they only wanted the user to be able to edit some columns of the row, not all of them. This meant they couldn’t use a client_writable() view.

So I put together something they could use instead: a wrapper class that makes some columns of a table row editable. Eg:

@anvil.server.callable
def get_writable_row():
  row = ...
  return RestrictedWritableRow(row, ['column_1', 'column_2']))

Now, on the client, I can do this:

row = anvil.server.call('get_writable_row')
row['column_2'] = 42 # This works
print(row['column_3']) # This works
row['column_3'] = 42 # This will fail, because column_3 isn't
                     # a writable column

Here’s a full example app: Anvil | Login


How it works is that RestrictedWritableRow is a Portable Class that wraps a Data Table row, and has a Capability that securely indicates the ID of the row and what columns can be edited.

When you try to update a column value on the RestrictedWritableRow class, the __setitem__ method calls a server function, passing the Capability and the row to update. The server function:

  • Unwraps the Capability, checking that it is a Capability of the right sort, and checking what row ID and which columns we gave the client permission to update
  • Checks that the ID of the row being updated, and the name of the column, matches what the Capability specified
  • Updates the row

This allows us to write our app logic very cleanly: ServerModule1 returns a list of RestrictedWritableRows for all the rows in our data table, and the UI uses data bindings to display that data in a DataGrid and update the notes column with data binding writeback – while making sure that the client can’t change the name column!

10 Likes

This is really helpful in so many cases. And it is a popular feature request as well. Can we please get native support for it?

Thank you, @meredydd! And your customer.

I’m sure this is one big reason why you created the “Portable Class” feature in the first place. Examples like this are needed. It will help make them more popular. The underlying concept, formal “capabilities”, has not seen much light or air, and so may be unfamiliar to many people. This puts it in a simple, easy-to-understand context, where it makes a great deal of sense. I’ll be studying it later.

@divyeshlakhotia , it may not be apparent from the above post, but if you click on Meredydd’s “Open in Anvil” link, you’ll get your own full, working copy of the code that makes this happen. Actual code that illustrates proper usage, that you can customize to fit your situation, plus the boilerplate that makes it work. I’ve got my own copy for study now.

Available now, by Meredydd’s (and their customer’s) generosity. Vs. waiting for it to become an official feature. The latter may take quite awhile, as they have many such requests, competing for their time. Plus, the new Beta IDE is surely (and justly) consuming a great deal of their time and attention.

One advantage of using Python, in Anvil, is that you can frequently build what you need, without waiting for an “official” shortcut. This is one case in point. An improved Anvil IDE, on the other hand, would be virtually impossible for an outside developer to build, without a perspective on Anvil’s internal structures and operations.

I know I’d rather have Anvil staff be working on things that I can’t do for myself.

6 Likes