Coding an Assessment

No autocompletion with simple objects, because the IDE doesn’t know what’s inside.

I often use simple objects to store data in the database, but I deserialize them into well designed classes as soon as I get them out of the database and never interact with them. I only interact with my objects.

I usually create one class (or hierarchy of classes) that takes care of the logic. In the class there is one function that (calls a server function and) gets the values from the database, then all the code uses objects, not dictionaries. My workflow is described here: [Wiki] Best practices: Test-driven development with Anvil

I would create something like this, one container class:

class KPIs(AttributeToKey):
    def __init__():
        items = anvil.server.call('get_kpis')
        self.items = [
            KPI.from_dict(item)
            for item in items
        ]
    
    def __getitem__(self, index):
        return self.items[index]

    @property
    def counter(self):
        # add properties to the collection
        return sum(1 for item in self.items if item.has_answer)

And one KPI class:

class KPI(AttributeToKey):
    @classmethod
    def from_dict(self, d):
        kpi = KPI()
        kpi._dict = d
        # I get some properties in the constructor
        kpi.prop1 = d.get('prop1', default_prop1)
        return kpi

    @property
    def prop2(self):
        # I calculate other properties in the accessor (usually the ones that are more complex than this one)
        return self.d['prop2']

With this setup, then you can do:

kpis = KPIs()
self.repeating_panel.items = kpis.items
print(kpis.counter)     # this works with code completion
print(kpis['counter'])  # no code completion, but it works with DataGrid databinding (which expects a dictionary like object)
print(kpis[0].prop1, kpis[0]['prop1'])
print(kpis[0].prop2, kpis[0]['prop2'])