Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When Expando Class should be used in Google App Engine Apps?

What are the applications for Google App Engine Expando Class? And what are the good practices related to it?

like image 775
fjsj Avatar asked Oct 24 '10 22:10

fjsj


1 Answers

Two common uses of Expandos are partially-fixed schemas and deleting old properties.

I frequently use Expando when I have a kind that needs slightly different properties across entities; in other words, when I need a 'partially' dynamic schema. One use-cases is an application that takes orders where some products are liquid (think water), some are physical units (think DVDs), and some are 'other' (think flour). Some fields, like item code, price and quantity, are always needed. But, what if the details of how quantity was computed is also needed?

Typically a fixed-schema solution would be to add a property for all of the variables we might use: weight, dimension, before and after weights of our stock, and so on. That sucks. For every entity most of the other fields are not needed.

class Order(db.Model):
    # These fields are always needed.
    item_code = db.StringProperty()
    unit_of_measure = db.StringProperty()
    unit_price = db.FloatProperty()
    quantity = db.FloatProperty()

    # These fields are used depending on the unit of measure.
    weight = db.FloatProperty()
    volume = db.FloatProperty()
    stock_start_weight = db.FloatProperty()
    stock_end_weight = db.FloatProperty()

With Expando we can do much better. We could use the unit_of_measure to tell us how we computed quantity. The functions that compute quantity can set the dynamic fields, and the functions that read that method's information know what to look for. And, the entity does not have a bunch of unneeded properties.

class Order(db.Expando):
    # Every instance has these fields.
    item_code = db.StringProperty()
    unit_of_measure = db.StringProperty()
    unit_price = db.FloatProperty()
    quantity = db.FloatProperty()


def compute_gallons(entity, kilograms, kg_per_gallon):
    # Set the fixed fields.
    entity.unit_of_measure = 'GAL'
    entity.quantity = kilograms / kg_per_gallon

    # Set the gallon specific fields:
    entity.weight = kilograms
    entity.density = kg_per_gallon

You could achieve a similar result by using a text or blob property and serializing a dict of 'other' value to it. Expando basically 'automates' that for you.

like image 109
Robert Kluin Avatar answered Oct 22 '22 08:10

Robert Kluin