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!