Romain
Romain

Reputation: 3758

New entity in repeated StructuredProperty stored as a _BaseValue

I have a HUser model (derived from Google's User class) which in turn contains 0 to n instances of social accounts. These accounts can be references to Facebook, Twitter or LinkedIn accounts. I have built an Account model, and defined a StructuredProperty in my User model with repeated=True, like this:

class Account(ndb.Expando):
    account_type = ndb.StringProperty(required=True, choices=['fb', 'tw', 'li'])
    account_id = ndb.StringProperty()
    access_token = ndb.StringProperty()
    ...

class HUser(User):
    email = ndb.StringProperty(required=True, validator=validate_email)
    created = ndb.DateTimeProperty(auto_now_add=True)
    accounts = ndb.StructuredProperty(Account, repeated=True)

If I only add Facebook or LinkedIn accounts to my user, everything works as expected. But the strange thing is, whenever I add a Twitter account, all subsequent accounts I add to that same user are stored as _BaseValue(Account()), and not Account() directly. So in my pages where I try to fetch accounts, I usually get errors like:

AttributeError: '_BaseValue' object has no attribute 'account_type'

I've read that these _BaseValue conversions are a bug in Google's ndb source code, but how can I get rid of it? Currently I'm using this awful workaround to bypass exceptions:

if type(account) == _BaseValue:
    account = account.b_val
    logging.warn("WARN: %s account %s was of type _BaseValue..." % (account.account_type, account.account_id))

Thanks for your help!

Upvotes: 2

Views: 814

Answers (1)

Patrick Costello
Patrick Costello

Reputation: 3626

How are you accessing your repeated property? ndb models store properties as _BaseValues and convert "seamlessly" (unfortunately not always the case) to your type (called the UserValue in ndb). Because of this, you have to be careful about how you store properties outside of your model. Consider this:

myUser = HUser(...)
accounts = myUser.accounts
myUser.put()
accounts[0] # This is a _BaseValue(Account)
myUser.accounts[0] # This is an Account

This is an open bug on the ndb issue tracker.

Upvotes: 7

Related Questions