Reputation: 3758
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
Reputation: 3626
How are you accessing your repeated property? ndb models store properties as _BaseValue
s 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