Звучит так, как будто вы должны использовать удаленную изолированную программную среду
Даже если вы заставите это работать, хранилище данных localhost по-прежнему будет вести себя не так, как фактическое хранилище данных.
Если вы действительно хотите смоделироватьв вашей производственной среде я бы порекомендовал настроить клон проекта вашего приложения в качестве удаленной песочницы.Вы можете развернуть свое приложение в новом gae project id appcfg.py update . -A sandbox-id
и использовать администратор хранилища данных, чтобы создать резервную копию продукции в облачном хранилище Google, а затем использовать администратора хранилища данных в своей песочнице, чтобы восстановить эту резервную копию в своей песочнице.
Клонирование производственных данных в localhost
Я заполняю свое хранилище данных localhost некоторыми производственными данными, но это не полный клон.Требуются только основные объекты и несколько тестовых пользователей.
Для этого я написал задание потока данных Google, которое экспортирует выбранные модели и сохраняет их в облачном хранилище Google в формате jsonl.Затем на локальном хосте у меня есть конечная точка с именем /init/
, которая запускает задание задачи для загрузки этих экспортов и их импорта.
Для этого я повторно использую код обработчика JSON REST, который может преобразовать любую модель вjson и наоборот.
Теоретически вы можете сделать это для всего хранилища данных.
EDIT - Вот как выглядит мой код to-json / from-json:
Все мои ndb.Model
подклассы my BaseModel
, которые имеют общий код преобразования:
get_dto_typemap = {
ndb.DateTimeProperty: dt_to_timestamp,
ndb.KeyProperty: key_to_dto,
ndb.StringProperty: str_to_dto,
ndb.EnumProperty: str,
}
set_from_dto_typemap = {
ndb.DateTimeProperty: timestamp_to_dt,
ndb.KeyProperty: dto_to_key,
ndb.FloatProperty: float_from_dto,
ndb.StringProperty: strip,
ndb.BlobProperty: str,
ndb.IntegerProperty: int,
}
class BaseModel(ndb.Model):
def to_dto(self):
dto = {'key': key_to_dto(self.key)}
for name, obj in self._properties.iteritems():
key = obj._name
value = getattr(self, obj._name)
if obj.__class__ in get_dto_typemap:
if obj._repeated:
value = [get_dto_typemap[obj.__class__](v) for v in value]
else:
value = get_dto_typemap[obj.__class__](value)
dto[key] = value
return dto
def set_from_dto(self, dto):
for name, obj in self._properties.iteritems():
if isinstance(obj, ndb.ComputedProperty):
continue
key = obj._name
if key in dto:
value = dto[key]
if not obj._repeated and obj.__class__ in set_from_dto_typemap:
try:
value = set_from_dto_typemap[obj.__class__](value)
except Exception as e:
raise Exception("Error setting "+self.__class__.__name__+"."+str(key)+" to '"+str(value) + "': " + e.message)
try:
setattr(self, obj._name, value)
except Exception as e:
print dir(obj)
raise Exception("Error setting "+self.__class__.__name__+"."+str(key)+" to '"+str(value)+"': "+e.message)
class User(BaseModel):
# user fields, etc
Мои обработчики запросов затем используют set_from_dto
& to_dto
, как это (BaseHandler
также обеспечивает некоторое удобствометоды для преобразования полезных нагрузок JSON в Python, а что нет):
class RestHandler(BaseHandler):
MODEL = None
def put(self, resource_id=None):
if resource_id:
obj = ndb.Key(self.MODEL, urlsafe=resource_id).get()
if obj:
obj.set_from_dto(self.json_body)
obj.put()
return obj.to_dto()
else:
self.abort(422, "Unknown id")
else:
self.abort(405)
def post(self, resource_id=None):
if resource_id:
self.abort(405)
else:
obj = self.MODEL()
obj.set_from_dto(self.json_body)
obj.put()
return obj.to_dto()
def get(self, resource_id=None):
if resource_id:
obj = ndb.Key(self.MODEL, urlsafe=resource_id).get()
if obj:
return obj.to_dto()
else:
self.abort(422, "Unknown id")
else:
cursor_key = self.request.GET.pop('$cursor', None)
limit = max(min(200, self.request.GET.pop('$limit', 200)), 10)
qs = self.MODEL.query()
# ... other code that handles query params
results, next_cursor, more = qs.fetch_page(limit, start_cursor=cursor)
return {
'$cursor': next_cursor.urlsafe() if more else None,
'results': [result.to_dto() for result in results],
}
class UserHandler(RestHandler):
MODEL = User