问题
I'm managing an API with using Google Cloud Endpoints and am struggling with a strange, randomly happening, error. The error happens in production only, the unit tests pass property.
I have the following model:
class UserFacebookData(ndb.Model):
facebook_id = ndb.StringProperty(required=True, indexed=True)
facebook_token = ndb.StringProperty(required=True, indexed=True)
class User(ndb.Model, Entity):
created = ndb.DateTimeProperty(auto_now_add=True, indexed=True)
username = ndb.StringProperty(indexed=True)
facebook_data = ndb.StructuredProperty(UserFacebookData, indexed=False)
And using this to create a user
ufd = UserFacebookData(facebook_id=some_api_data, facebook_token=some_api_data)
user = User(username=some_api_data, facebook_data=ufd)
user.save()
or to update one
ufd = UserFacebookData(facebook_id=some_api_data, facebook_token=some_api_data)
user = get_from_db(some_api_data)
user.facebook_data = ufd
user.save()
(Edit: save() is a method of the parent Entity class, doing a put() + some memcached stuff)
And got, from time to time when updating the user, the following error
Expected UserFacebookData instance,
got UserFacebookData(facebook_id=u'xxx', facebook_token=xxx'))
Yet, traces (to print and check type of the ufd / UserFacebookData instance) showed that it's correctly created and that the user also exists
# print user.username
my_username
# print UserFacebookData
UserFacebookData(facebook_id=u'xx', facebook_token=xx')
# print type(UserFacebookData)
UserFacebookData<facebook_id=StringProperty('facebook_id', required=True),
facebook_token=StringProperty('facebook_token', required=True)>
I can't see what I'm missing. Has someone already experiences that - and hopefully fixed it? Here's the full error stack
Encountered unexpected error from ProtoRPC method implementation: BadValueError (Expected UserFacebookData instance, got UserFacebookData(facebook_id=u'xx', facebook_token=xx'))
Traceback (most recent call last):
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/protorpc-1.0/protorpc/wsgi/service.py", line 181, in protorpc_service_app
response = method(instance, request)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/endpoints-1.0/endpoints/api_config.py", line 1329, in invoke_remote
return remote_method(service_instance, request)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/protorpc-1.0/protorpc/remote.py", line 412, in invoke_remote_method
response = method(service_instance, request)
File "/base/data/home/apps/s~yapme-web/alpha2.377359917212322950/api/helpers.py", line 43, in method
return func(*args, **kwargs)
File "/base/data/home/apps/s~xx-web/alpha2.377359917212322950/api/user.py", line 25, in users_create
user = User.create(request)
File "/base/data/home/apps/s~xx-web/alpha2.377359917212322950/entities/users.py", line 168, in create
user.facebook_data = facebook_data
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 1339, in __set__
self._set_value(entity, value)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 1084, in _set_value
value = self._do_validate(value)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 1031, in _do_validate
value = self._call_shallow_validation(value)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 1223, in _call_shallow_validation
return call(value)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 1270, in call
newvalue = method(self, value)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 2269, in _validate
(self._modelclass.__name__, value))
BadValueError: Expected UserFacebookData instance, got UserFacebookData(facebook_id=u'xx', facebook_token=xx')
回答1:
save()
is not ndb syntax. I think you want put()
. Also, you should be able to just use a dict to set the StructuredProperty values:
To create a user:
ufd = {"facebook_id":some_api_data, "facebook_token":some_api_data}
user = User(username=some_api_data, facebook_data=ufd)
user.put()
To update a user:
ufd = {"facebook_id":some_api_data, "facebook_token":some_api_data}
user = get_from_db(some_api_data)
user.facebook_data = ufd
user.put()
This should allow you to save both at the same time. Otherwise, you may end up with a problem with eventual consistency. This is most likely the issue, as you say it only happens intermittently, in production.
回答2:
I had the same problem, and have posted the answer here: App Engine BadValueError when saving ndb LocalStructured entity. Basically the problem was caused by a relative import, so that python thinks FooBar are in different packages.
来源:https://stackoverflow.com/questions/24869911/gae-endpoints-error-expected-foobar-instance-got-foobar