def key_for_namespace(cls, namespace): """Return the Key for a namespace. Args: namespace: A string giving the namespace whose key is requested. Returns: The Key for the namespace. """ if namespace: return model.Key(cls.KIND_NAME, namespace) else: return model.Key(cls.KIND_NAME, cls.EMPTY_NAMESPACE_ID)
def get(self, name): NOT_SET_VALUE = u'!!!__ NOT SET __!!!' entity = self(key=model.Key(self, name)) entity.populate(value=NOT_SET_VALUE) txn = lambda: entity.put() if not entity.key.get() else entity.key retval = model.transaction(txn).get() # Fall back to environment vars if retval.value == NOT_SET_VALUE: fallback_value = environ.get(name) if fallback_value is not None: retval.value = fallback_value retval.put() return fallback_value if retval.value == NOT_SET_VALUE: logging.error( ('%s %s not found in the database. A placeholder ' + 'record has been created. Go to the Developers Console ' 'for your app in App Engine, look up the Settings record ' 'with name=%s and enter its value in that record\'s value ' 'field.') % (self.__name__, name, name)) return retval.value
def delete_multi(cls, values): """Deletes multiple unique values at once. :param values: A sequence of values to be deleted. """ return model.delete_multi(model.Key(cls, v) for v in values)
def create_multi(cls, values): """Creates multiple unique values at once. :param values: A sequence of values to be unique. See :meth:`create`. :returns: A tuple (bool, list_of_keys). If all values were created, bool is True and list_of_keys is empty. If one or more values weren't created, bool is False and the list contains all the values that already existed in datastore during the creation attempt. """ # Maybe do a preliminary check, before going for transactions? # entities = model.get_multi(keys) # existing = [entity.key.id() for entity in entities if entity] # if existing: # return False, existing # Create all records transactionally. keys = [model.Key(cls, value) for value in values] entities = [cls(key=key) for key in keys] func = lambda e: e.put() if not e.key.get() else None created = [model.transaction(lambda: func(e)) for e in entities] if created != keys: # A poor man's "rollback": delete all recently created records. model.delete_multi(k for k in created if k) return False, [k.id() for k in keys if k not in created] return True, []
def remove_unique(cls, auth_id, unique_properties, **user_values): uniques = [('%s.auth_id:%s' % (cls.__name__, auth_id), 'auth_id')] print uniques if unique_properties: for name in unique_properties: key = '%s.%s:%s' % (cls.__name__, name, user_values[name]) uniques.append((key, name)) # Delete the uniques ndb.delete_multi(model.Key(cls.unique_model, k) for k, v in uniques)
def get_multi_async(cls, blob_keys, **ctx_options): """Async version of get_multi().""" for blob_key in blob_keys: if not isinstance(blob_key, (BlobKey, six.string_types)): raise TypeError('Expected blob key, got %r' % (blob_key, )) if 'parent' in ctx_options: raise TypeError('Parent is not supported') blob_key_strs = list(map(str, blob_keys)) keys = [model.Key(BLOB_INFO_KIND, id) for id in blob_key_strs] return model.get_multi_async(keys, **ctx_options)
def key_for_entity_group(cls, key): """Return the key for the entity group containing key. Args: key: a key for an entity group whose __entity_group__ key you want. Returns: The __entity_group__ key for the entity group containing key. """ return model.Key(cls.KIND_NAME, cls.ID, parent=key.root())
def key_for_kind(cls, kind): """Return the __property__ key for kind. Args: kind: kind whose key is requested. Returns: The parent key for __property__ keys of kind. """ return model.Key(Kind.KIND_NAME, kind)
def key_for_kind(cls, kind): """Return the __kind__ key for kind. Args: kind: kind whose key is requested. Returns: The key for kind. """ return model.Key(cls.KIND_NAME, kind)
def key_for_property(cls, kind, property): """Return the __property__ key for property of kind. Args: kind: kind whose key is requested. property: property whose key is requested. Returns: The key for property of kind. """ return model.Key(Kind.KIND_NAME, kind, Property.KIND_NAME, property)
def send_live_message(key): """Deferred task for sending messages to the open channels.""" message_key = model.Key(urlsafe=key) message = message_key.get() if message is None: return # Only notify rescent connections timestamp = datetime.datetime.now() oldest = timestamp - datetime.timedelta(hours=2) connections = Connection.query().filter(Connection.timestamp >= oldest).fetch(200, keys_only=True) for connection in connections: channel.send_message(connection.id(), message.to_json())
def get_key(cls, user, subject, token): """Returns a token key. :param user: User unique ID. :param subject: The subject of the key. Examples: - 'auth' - 'signup' :param token: Randomly generated token. :returns: ``model.Key`` containing a string id in the following format: ``{user_id}.{subject}.{token}.`` """ return model.Key(cls, '%s.%s.%s' % (str(user), subject, token))
def add_commit(cls, key): commit_key = model.Key(urlsafe=key) commit = commit_key.get() parent_key = commit_key.parent() if parent_key is None: return parent = parent_key.get() picture_url = getattr(parent, 'picture_url', '/static/images/spread_the_word_button.png') message = cls(username=parent.username, picture_url=picture_url, message=commit.message[:200], url=commit.url, project=commit.project, commit_hash=commit.hash) message.put() deferred.defer(send_live_message, message.key.urlsafe(), _queue="live") return message
def create(cls, value): """Creates a new unique value. :param value: The value to be unique, as a string. The value should include the scope in which the value must be unique (ancestor, namespace, kind and/or property name). For example, for a unique property `email` from kind `User`, the value can be `User.email:[email protected]`. In this case `User.email` is the scope, and `[email protected]` is the value to be unique. :returns: True if the unique value was created, False otherwise. """ entity = cls(key=model.Key(cls, value)) txn = lambda: entity.put() if not entity.key.get() else None return model.transaction(txn) is not None
def get_by_auth_token(cls, user_id, token): """Returns a user object based on a user ID and token. :param user_id: The user_id of the requesting user. :param token: The token string to be verified. :returns: A tuple ``(User, timestamp)``, with a user object and the token timestamp, or ``(None, None)`` if both were not found. """ token_key = cls.token_model.get_key(user_id, 'auth', token) user_key = model.Key(cls, user_id) # Use get_multi() to save a RPC call. valid_token, user = model.get_multi([token_key, user_key]) if valid_token and user: timestamp = int(time.mktime(valid_token.created.timetuple())) return user, timestamp return None, None
def create_user(cls, auth_id, unique_properties=None, **user_values): """Creates a new user (calls the original webapp2.auth.User.create_user. However, when the user creation fails due to an exception (e.g. when a required property isn't provided), we'll clean up and delete any unique properties created alongside the user model.""" try: # Call original create_user method return super(User, cls).create_user(auth_id, unique_properties, **user_values) except Exception, exc: # Since the original create_user method calls user.put() (where the exception occurs), only *after* # calling cls.unique_model.create_multi(k for k, v in uniques), this means we'll have to delete # those created uniques (other they'll just stay as garbage data in the DB, while not allowing # the user to re-register with the same username/email/etc. uniques = [('%s.auth_id:%s' % (cls.__name__, auth_id), 'auth_id')] if unique_properties: for name in unique_properties: key = '%s.%s:%s' % (cls.__name__, name, user_values[name]) uniques.append((key, name)) # Delete the uniques ndb.delete_multi(model.Key(cls.unique_model, k) for k,v in uniques) # Continue throwing the original exception raise exc
def set(self, name, inputValue): entity = self(key=model.Key(self, name)) entity.populate(value=inputValue) entity.put()
def put(self, entity, **ctx_options): options = _make_ctx_options(ctx_options) key = entity._key if key is None: key = model.Key(entity.__class__, None) use_datastore = self._use_datastore(key, options) use_memcache = None memcache_deadline = None if entity._has_complete_key(): use_memcache = self._use_memcache(key, options) if use_memcache: memcache_deadline = self._get_memcache_deadline(options) mkey = self._memcache_prefix + key.urlsafe() ns = key.namespace() if use_datastore: yield self.memcache_set(mkey, _LOCKED, time=_LOCK_TIME, namespace=ns, use_cache=True, deadline=memcache_deadline) else: pbs = entity._to_pb( set_key=False).SerializePartialToString() if len(pbs) > memcache.MAX_VALUE_SIZE: raise ValueError( 'Values may not be more than %d bytes in length; ' 'received %d bytes' % (memcache.MAX_VALUE_SIZE, len(pbs))) timeout = self._get_memcache_timeout(key, options) yield self.memcache_set(mkey, pbs, time=timeout, namespace=ns, deadline=memcache_deadline) if use_datastore: key = yield self._put_batcher.add(entity, options) if not isinstance(self._conn, datastore_rpc.TransactionalConnection): if use_memcache is None: use_memcache = self._use_memcache(key, options) if use_memcache: mkey = self._memcache_prefix + key.urlsafe() ns = key.namespace() yield self.memcache_delete(mkey, namespace=ns, deadline=memcache_deadline) if key is not None: if entity._key != key: logging.info('replacing key %s with %s', entity._key, key) entity._key = key if self._use_cache(key, options): self._cache[key] = entity raise tasklets.Return(key)