Adding derived properties to LiveObject

I have a server.callable that returns a list of LiveObjects (rows in my table). I want to compute a derived property and add it to the LiveObject on the serverside.

Calling my_row["my_prop"] = compute_prop() adds a column to my data table. How to I access this property via a self.item["my_prop"] call on the frontend without adding the property to my data table?

Hello and welcome,

I do not believe you can add data to a LiveObject without changing the DataTable.

However, DataTable rows are similar to dictionaries. This means that on the server you can cast a LiveObject row to a dictionary:

my_dict=dict(my_row)

For multiple rows you will need to loop.

With this approach you can compute whatever you wish, update your dict, and return it to the client. On the client side you would then set data bindings to this dictionary accordingly.

Please see here for more information

The problem is that then that object does not have the useful methods like .update and .get_id which I need to use. Perhaps SerializableObject will help here? @meredydd

Dictionaries have an update method and you can fairly easily add the row’s ID when you cast things; a one-liner if you use list comprehensions. Yes, you would then have to re-update your datatable as needed. I like to use the **kwargs for that.

I may have misunderstood your question.

Are you asking how to access a property in your datatable from the client?

If you update a LiveObject, you should be able to access the new data as you normally would.

It sounds as though you want to avoid adding data to the datatable after some computation, in which case I’d say to use dictionaries.

I want to add a property that is computed on the backend and accessible on the frontend with self.item["my_prop"] while still retaining the LiveObject API on the frontend and not adding a column to the datatables.

LiveObject.update method syncs the information with app_tables while dict.update method just updates the object with the provided keys.

One solution that would be cool would be a LiveObject subclass that uses @property with __getitem__ and __setitem__ to memoize derived properties. However, calling MyRow as a constructor may be an issue given that app_tables.search returns LiveObjects nested in LiveObjects (for linked tables) so ORM configuration is required unless you always pass the results of an app_tables query through a factory. Another solution would be to disable the database syncing for __setitem__ on certain properties, again with some sort of ORM configuration. Hopefully there is already a simple solution that I’m not thinking of.

class MyRow(LiveObject):

    def expensive_computation(self):
        sleep(5)
        return "bar"

    def invalidate_derived_properties(self):
        self._my_prop = None

    @property
    def my_prop(self):
        if self._my_prop is None:
            self._my_prop = self.expensive_computation()
        return self._my_prop

    def __getitem__(self, key):
        if key == "my_prop":
             return self.my_prop
        return super().__getitem__(key)

    def __setitem__(self, key, val):
        if key == "my_prop":
             raise Exception("You cannot set a derived property.")
        return super().__setitem__(key, val)

As I suggested, one way of doing this would be as follows:

# on server
items=[{'rows': r, 'new_age': r['age']+1} for r in app_tables.my_table.search()]

Here some computation is done without affecting the DataTable. All the while, the actual row is returned. Therefore, you still have access to the usual DataTable methods. Further, you can set you data binding on the client to any aspect of the returned list (i.e., columns in your DataTable or keys from your dict).

Perhaps there are other solutions one may take.