diff --git a/bones/relationalBone.py b/bones/relationalBone.py index 5123e72..1b30481 100644 --- a/bones/relationalBone.py +++ b/bones/relationalBone.py @@ -1,15 +1,9 @@ # -*- coding: utf-8 -*- from server.bones import baseBone from server.bones.bone import getSystemInitialized -from server import db -from server.errors import ReadFromClientError -from server.utils import normalizeKey -from google.appengine.api import search -import extjson +from server import db, conf, utils, errors from time import time -from datetime import datetime -import logging - +import logging, extjson class relationalBone( baseBone ): """ @@ -251,6 +245,9 @@ def serialize(self, valuesCache, name, entity ): return entity def postSavedHandler( self, valuesCache, boneName, skel, key, dbfields ): + if boneName not in valuesCache: + return + if not valuesCache[boneName]: values = [] elif isinstance( valuesCache[boneName], dict ): @@ -401,10 +398,9 @@ def fromClient( self, valuesCache, name, data ): try: entry = db.Get( db.Key( r["dest"]["key"] ) ) - except: #Invalid key or something like thatmnn + except: #Invalid key or something like that + logging.info("Invalid key %r detected on bone '%s'", r["dest"]["key"], name) - logging.info( "Invalid reference key >%s< detected on bone '%s'", - r["dest"]["key"], name ) if isinstance(oldValues, dict): if oldValues["dest"]["key"]==str(r["dest"]["key"]): refSkel = self._refSkelCache @@ -473,7 +469,7 @@ def fromClient( self, valuesCache, name, data ): if val is None: errorDict[name] = "No value selected" if len(errorDict.keys()): - return ReadFromClientError(errorDict, forceFail) + return errors.ReadFromClientError(errorDict, forceFail) def _rewriteQuery(self, name, skel, dbFilter, rawFilter ): """ @@ -743,7 +739,7 @@ def updateInplace(relDict): logging.error("Invalid dictionary in updateInplace: %s" % valDict) return - entityKey = normalizeKey(originalKey) + entityKey = utils.normalizeKey(originalKey) if originalKey != entityKey: logging.info("Rewriting %s to %s" % (originalKey, entityKey)) valDict["key"] = entityKey @@ -773,7 +769,7 @@ def updateInplace(relDict): if not valuesCache[boneName]: return - logging.info("Refreshing relationalBone %s of %s" % (boneName, skel.kindName)) + logging.debug("Refreshing relationalBone %s of %s" % (boneName, skel.kindName)) if isinstance(valuesCache[boneName], dict): updateInplace(valuesCache[boneName]) @@ -861,16 +857,34 @@ def setBoneValue(self, valuesCache, boneName, value, append, *args, **kwargs): def relSkelFromKey(key): if not isinstance(key, db.Key): key = db.Key(encoded=key) + if not key.kind() == self.kind: logging.error("I got a key, which kind doesn't match my type! (Got: %s, my type %s)" % (key.kind(), self.kind)) return None - entity = db.Get(key) - if not entity: - logging.error("Key %s not found" % str(key)) - return None + + try: + entity = db.Get(key) + + except: + notFoundStrategy = conf.get("viur.bone.relational.notFoundStrategy", "raise").lower() + + if notFoundStrategy == "raise": + raise + elif notFoundStrategy == "report": + logging.error("Key %r not found", key) + return None + + entity = None + relSkel = RefSkel.fromSkel(skeletonByKind(self.kind), *self.refKeys) - relSkel.unserialize(entity) + + if entity: + relSkel.unserialize(entity) + else: + relSkel["key"] = key + return relSkel + if append and not self.multiple: raise ValueError("Bone %s is not multiple, cannot append!" % boneName) if not self.multiple and not self.using: diff --git a/config.py b/config.py index 747c4d7..5ffd82b 100644 --- a/config.py +++ b/config.py @@ -18,6 +18,8 @@ "viur.capabilities": [], #Extended functionality of the whole System (For module-dependend functionality advertise this in the module configuration (adminInfo) "viur.contentSecurityPolicy": None, #If set, viur will emit a CSP http-header with each request. Use the csp module to set this property + "viur.bone.relational.notFoundStrategy": "raise", # Strategy to run when a relationalBone doesn't find its entries. Valid are: "raise", "report", "ignore" + "viur.db.caching" : 2, #Cache strategy used by the database. 2: Aggressive, 1: Safe, 0: Off "viur.debug.traceExceptions": False, #If enabled, user-generated exceptions from the server.errors module won't be caught and handled "viur.debug.traceExternalCallRouting": False, #If enabled, ViUR will log which (exposed) function are called from outside with what arguments