I wanted to return a database Row to the client, but also manipulate some column values temporarily just for that client session, so I made a portable class that allows me to do that and still get the row’s id normally:
import anvil.server
import anvil.users
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
@anvil.server.portable_class
class DbRow():
def __init__(self, _db_row: tables.Row, extra_info: dict=None):
self._db_row = _db_row
self.extra_info = extra_info
def __getitem__(self, column_key):
try:
return self._db_row[column_key]
except tables.NoSuchColumnError:
try:
return self.extra_info[column_key]
except (KeyError, TypeError):
raise tables.NoSuchColumnError(f"No such column '{column_key}'")
def get_id(self):
return self._db_row.get_id()
1 Like
I like it!
A similar approach could be used to create a mutable object for use with write back data bindings that you could then pass back to the server to finalize the updates to the data table.
1 Like
Good thought!
import anvil.server
import anvil.users
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
@anvil.server.portable_class
class DbRow():
def __init__(self, db_row: tables.Row, extra_info: dict=None):
self._db_row = db_row
self._extra_info = extra_info or {}
self._update_info = {}
def __getitem__(self, column_key):
try:
return self._db_row[column_key]
except tables.NoSuchColumnError:
try:
return self._extra_info[column_key]
except KeyError:
raise tables.NoSuchColumnError(f"No such column '{column_key}'")
def __setitem__(self, column_key, value):
if column_key in self._db_row:
self._update_info[column_key] = value
else:
self._extra_info[column_key] = value
def get_id(self):
return self._db_row.get_id()
def update(self, update_data: dict=None, update_db_now=True):
if update_data:
self._update_info = {**self._update_info, **update_data}
if update_db_now and self._update_info:
self._db_row.update(self._update_info)
self._update_info = {}
1 Like
getitem
would also need to check to see if the data was in update_info
before checking the db_row
, right?
I considered it, and I don’t think its necessarily wrong, but for my implementation at the current moment I want to just get the current database value until I have actually sent the update.
Aaaaand I almost immediately found a use for that functionality, though only conditionally:
import anvil.server
import anvil.users
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
@anvil.server.portable_class
class DbRow:
def __init__(
self, db_row: tables.Row, extra_info: dict = None, use_updated_values=False
):
self._db_row = db_row
self._extra_info = extra_info or {}
self.use_updated_values = use_updated_values
self.update_info = {}
def __getitem__(self, column_key):
if self.use_updated_values:
try:
return self.update_info[column_key]
except KeyError:
# Getting values from row or extra info already handled
pass
try:
return self._db_row[column_key]
except (tables.NoSuchColumnError, TypeError):
try:
return self._extra_info[column_key]
except KeyError:
raise tables.NoSuchColumnError(f"No such column '{column_key}'")
def __setitem__(self, column_key, value):
if column_key in self._db_row:
self.update_info[column_key] = value
else:
self._extra_info[column_key] = value
def get_id(self):
return self._db_row.get_id()
def update(self, update_data: dict = None, update_db_now=True):
if update_data:
self.update_info = {**self.update_info, **update_data}
if update_db_now and self.update_info:
self._db_row.update(self.update_info)
self.update_info = {}