Fabio Moggi
Fabio Moggi

Reputation: 449

Google App Engine Datastore modeling issue

There has been tons of questions on how to properly do data modeling when moving from traditional relational database to non-relational database such as the App Engine Datastore.

I have read the NDB official documentation many times and tried a couple of tutorials on the internet, however, I am still stucked.

I am developing a financial application that captures all my personal expenses. This means I have designed an entity called Expense with a few properties on it. As part of an Expense, I also designed a Vendor entity to store information related to merchant.

Here is the implementation:

class Expense(ndb.Model):
    amount = ndb.FloatProperty(required=False)
    description = ndb.StringProperty()
    vendor = ndb.KeyProperty(kind=Vendor)

class Vendor(ndb.Model):
    companyName = ndb.StringProperty(required=False)
    friendlyName = ndb.StringProperty(required=False, default="")

This is the code to retrieve the Expense information:

def get(self):
    template_page = "expense.html"
    template_values = {'expense':Expense.query()}

    self.renderTemplatePage(template_page, template_values)

The problem I am facing with the design above is how to retreive Expense and Vendor information and pass it to JINJA to render it. As I can expect, the Vendor property in the Expense class is just a Key and not the object itself. So JINJA cannot understand the expression {{expense.vendor.friendlyName}}

Although the problem seems to be technical, I believe my dificulty is related to the concept of non-relational database and the traditional-like design I applied to the solution.

An alternative is to use StructuredProperty instead of KeyPrperty. However, one solution requirement is to be able to rename a vendor friendly name and that should affect all exiting expenses. It is insane to go after each stuctured property and find the changes.

Before giving up on App Engine and moving to Google Cloud SQL, I would like to hear some advice on how to solve this data modeling scenario. Maybe the solution I need to build is not recommended for non-relational database.

Thansk for any support on that.

Upvotes: 1

Views: 120

Answers (1)

Greg
Greg

Reputation: 10360

In your template you could do:

{{ expense.vendor.get().friendlyName }}

Or you could add a property to your model:

class Expense(ndb.Model):
    amount = ndb.FloatProperty(required=False)
    description = ndb.StringProperty()
    vendor = ndb.KeyProperty(kind=Vendor)

    @property
    def vendor_name(self):
      return self.vendor.get().friendlyName

That will allow in your template:

{{ expense.vendor_name }}

To stop this being so inefficient, you can fetch the vendors before you display your expense-list, making the calls to get inside the loop just local-memory lookups:

def get(self):
    template_page = "expense.html"
    expenses = Expense.query().fetch()
    ndb.get_multi([e.vendor for e in expenses])
    template_values = {'expense':expenses}

    self.renderTemplatePage(template_page, template_values)

Upvotes: 2

Related Questions