Anvil’s great strength is that you can do everything in Python – browser-side and server-side, with just a function call from one to the other.
We’ve just launched a new feature that goes one step further: You can now define your own classes that can be passed between Forms, Server Modules and even Uplink code! Check out an example from our announcement post:
It’s easy to get started, but it’s also heavily customisable. You can control how your objects are serialised and sent over the network, and even use our built-in Capability support to create Data-Tables-like APIs that embed permissions in the objects you return. I’m excited to see what some of our more advanced users do with it!
I’m curious how this plays with the lazy search iterators? When you have code like
return [Video(row['id'], is_admin)
for row in app_tables.videos.search(owner=user)]
That’s requiring it to iterate through all the rows that match the query, right? So if we have a case where we have enough rows matching that we don’t want to return everything all at once, we’re better off sticking with search iterators?
I love the capabilities, just trying to wrap my mind around when I’d want to use portable objects/capabilities, and when I’d want to stick with search iterators.
I built a paging search function into my ORM library.
It caches the search iterator from the data tables query on the server side and returns ‘pages’ of portable objects from there as the client requests them.
@jshaffstall, you’re right that the little code sample I provided searches through all rows of a search iterator. However, it’s entirely possible to use Portable Classes to build your own lazy iterator! The simplest way, if you’re OK with sending the Data Tables search iterator to the client, is to send it as a private attribute of a Portable Class.
Here’s an example that wraps a search iterator, and dynamically instantiates objects:
class PotatoSack:
def __init__(self):
self._search = app_tables.potatoes.search()
def __iter__(self):
return iter((Potato(row['weight'], row['temperature']) for row in self._search))
Or you could build a lazy iterator entirely yourself, implementing __iter__ and __next__ and calling a server function that gives you a “page” of results at a time. (This is what Owen’s library does.)
If you were using capabilities, you’d want the PotatoSack to have a Capability on, say, ['potatoes'] (or a narrower capability permitting access only to a particular subset), and then hand each Potato a narrowed capability on, say, ['potatoes', 'potato_253'].
Unless I’m doing something silly, it seems the Portable Classes fail with dictionaries where the keys are numeric still. I’ve added some detail about this in my original feature request here: Serialising dictionary with numeric keys
That’s right, @AWSOM – adding support for Portable Classes doesn’t change the other restrictions on which data types are portable, which are fully documented here:
For all and sundry regarding the “Capability” model
The term “Capability” was hijacked, for a specific formal, technical use, long before our friends at Anvil came along. Anvil uses it in this formal sense, not in the colloquial sense.