Перенос данных из хранилища данных продукта в хранилище данных локальной среды разработки в Google App Engine (Python) - PullRequest
0 голосов
/ 11 октября 2018

TL; DR Мне нужно найти реальное решение для загрузки моих данных из хранилища данных продукта и загрузки их в локальную среду разработки.

Подробная проблема:

Мне нужно проверить своиприложение на локальном сервере разработки с реальными данными (не в реальном времени) о хранилище данных сервера продукта.Документация и другие ресурсы предлагают три варианта:

  1. Использование appfg.py загрузки данных с сервера продукта с последующей загрузкой в ​​локальную среду разработки.Когда я использую этот метод, я получаю ошибку «неверный запрос» из-за проблемы с Oauth.Кроме того, этот метод будет устаревшим.Официальная документация рекомендует использовать второй метод:
  2. Использование gcloud через управляемый экспорт и импорт .Эпическая документация этого метода объясняет, как мы резервируем все данные на консоли (в https://console.cloud.google.com/). я пробовал этот метод. Резервные данные генерируются в хранилище в облаке. Я скачал их. Это в формате LevelDBМне нужно загрузить его на локальный сервер разработки. Официального объяснения этому нет. Метод загрузки первого метода несовместим с форматом LevelDB. Не удалось найти официальный способ решения проблемы. Существует Запись StackOverflow , но она не работает для меня, потому что она просто получает все сущности как dict. Диалог объекта 'dic' с сущностями 'ndb' становится сложной проблемой.
  3. IЯ потерял надежду на первые два метода, а затем решил использовать Cloud Datastore Emulator (beta) , который обеспечивает эмуляцию реальных данных в локальной среде разработки. Это все еще бета и имеет несколько проблем. Когда я запускаюкоманда, с которой я столкнулся с проблемой DATASTORE_EMULATOR_HOST в любом случае.

1 Ответ

0 голосов
/ 11 октября 2018

Звучит так, как будто вы должны использовать удаленную изолированную программную среду

Даже если вы заставите это работать, хранилище данных 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...