You are currently viewing the new Anvil Editor Docs.
Switch to the Classic Editor Docs
You are currently viewing the Classic Editor Docs.
Switch to the new Anvil Editor Docs

Writing Portable Classes

By default, Anvil already knows how to pass many basic Python objects between client and server code. But if you want to pass more complicated objects, you can define your own classes that can be passed from server to client code. We call these portable classes.

To make a class portable, you can decorate it with anvil.server.portable_class. You can then use instances of this class as arguments to (or return values from) Server Functions.

If you want a class to be portable, it needs to follow two main rules:

First, the class definition needs to be accessible to both client and server code, so it should go in an Anvil Module (not a Server Module). Here’s an example:

# In a module called, say, 'my_classes'...
import anvil.server

@anvil.server.portable_class
class Person():
    
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def get_full_name(self):
        return self.first_name + " " + self.last_name

Now we can return an instance of the Person class from a server function, and it will arrive fully-formed on the client:

# In a Server Module...
from my_classes import Person

@anvil.server.callable
def get_person():
    # Look up the person - in a database, perhaps.
    return Person("John", "Smith") 
# Then, on the client...

p = anvil.server.call("get_person")
print(p.get_full_name()) # --> John Smith

Notice that the object returned from the server was a full instance of the Person class. Anvil took care of serialising all the object’s attributes, transmitting it, and deserialising it when it arrived. Of course, this works the other way too - you can pass instances of portable classes as arguments to Server Functions too.

Secondly, for a class to serialise correctly, all its attributes need to be values that Anvil can serialise - including instances of other portable classes! You must also avoid circular references - ie if object A refers to object B, then object B can’t contain a reference to object A.

When you pass a portable object between client and server, it is copied. So, for example, if you pass a Person instance to a server function that returns its argument, the return value from the anvil.server.call() is a new instance.

(The same goes for your class’s attributes: For example, if you have two attributes referring to the same dict object, they will deserialise to two separate objects at the other end. If you need more precise control over serialisation, you can customise how your class is serialised.)

In order for uplink code to serialise and deserialise a portable class, the class should be registered with the same unique name in both your app code and in your uplink code. By default the anvil.server.portable_class decorator registers a portable class based on its module and name. To register a portable class with a unique name, pass the name to the decorator.

# use a unique name to register this class

@anvil.server.portable_class('_Person')
class Person():
    def __init__(self, first_name, last_name):
        ...

More powerful control

You can customise your portable classes for efficiency, or to enforce permissions:

Custom Serialisation

By default, Anvil transmits all of a portable object’s attributes. By implementing the __serialize__ and __deserialize__ methods, you can control precisely how your data is transmitted.

Capabilities

Client code is untrusted - a malicious user can make their browser do anything! Sometimes, you want your objects to have unforgeable identities, so that clients can only perform operations if the server code has given them permission. Anvil’s Capability objects make this easy.

Capability-scoped cache updates

The portable objects you pass to the client might represent some long-lived underlying object in your app’s data model. To avoid round-trips, you might want to pass some information around with that object so it can be accessed quickly from client code – in other words, cached data. But when you call a server function to update that object, you want to update the client side cache too. And to avoid data leaks, you need to send updates only if this is an object the client already knows about. Anvil includes a mechanism for secure capability-scoped cache updates to make this easy.


Do you still have questions?

Our Community Forum is full of helpful information and Anvil experts.