{"id":1887,"date":"2009-11-25T11:56:35","date_gmt":"2009-11-25T02:56:35","guid":{"rendered":"http:\/\/fukata.org\/?p=1887"},"modified":"2017-08-11T22:59:08","modified_gmt":"2017-08-11T22:59:08","slug":"gae-p-validationmanager","status":"publish","type":"post","link":"https:\/\/blog.fukata.org\/archives\/1887\/","title":{"rendered":"[GAE\/P]\u72ec\u81ea\u306eValidationManager\u3092\u4f5c\u3063\u3066\u307f\u307e\u3057\u305f"},"content":{"rendered":"
GAE\u3067\u30a2\u30d7\u30ea\u3092\u4f5c\u6210\u3057\u3066\u3044\u3066\u3001\u5165\u529b\u5024\u3078\u306e\u691c\u8a3c\u6a5f\u69cb\u304c\u8ca7\u5f31\u3060\u3068\u601d\u3063\u305f\u306e\u3067\u3001\u4f5c\u308a\u307e\u3057\u305f\u3002\u4eca\u56de\u4f5c\u6210\u3057\u305f\u306e\u306f\u3001\u691c\u8a3c\u60c5\u5831\u3092yaml\u306b\u8a18\u8ff0\u3057\u3001\u305d\u306e\u691c\u8a3c\u60c5\u5831\u306b\u6cbf\u3063\u3066\u30e2\u30c7\u30eb\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u8d70\u67fb\u3057\u3066\u3044\u304f\u3068\u3044\u3046\u7269\u3067\u3059\u3002<\/p>\n
\u691c\u8a3c\u60c5\u5831yaml\u306e\u8a18\u8ff0\u65b9\u6cd5\u3001\u4f7f\u3044\u65b9\u3068\u3082\u306bSymfony\u306eValidationManager\u306b\u9177\u4f3c\u3057\u3066\u3044\u308b\u3068\u601d\u3044\u307e\u3059\u3002\u306a\u306e\u3067\u3001Symfony\u3092\u4f7f\u3063\u305f\u3053\u3068\u304c\u3042\u308b\u4eba\u3067\u3042\u308c\u3070\u3001\u306a\u3093\u3068\u306a\u304f\u308f\u304b\u308a\u3084\u3059\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002\u3068\u8a00\u3063\u3066\u3082\u3001Symfony\u306eValidationManager\u307b\u3069\u307e\u3060\u7d30\u90e8\u307e\u3067\u30a8\u30e9\u30fc\u30c1\u30a7\u30c3\u30af\u306a\u3069\u3092\u3057\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u691c\u8a3c\u60c5\u5831yaml\u306e\u8a18\u8ff0\u306b\u3088\u3063\u3066\u306f\u3001\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3059\u308b\u3068\u601d\u3044\u307e\u3059\u3002\u3067\u3059\u306e\u3067\u3001\u3053\u306e\u8fba\u306f\u3001\u3082\u3046\u5c11\u3057\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u3092\u3057\u306a\u3044\u3068\u3044\u3051\u306a\u3044\u304b\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n
Python\u306b\u3088\u308b\u30ea\u30d5\u30ec\u30af\u30b7\u30e7\u30f3\u90e8\u5206\u3060\u3063\u305f\u308adb.Model\u306e\u6271\u3044\u65b9\u304c\u3082\u3057\u9593\u9055\u3063\u3066\u3044\u305f\u3089\u662f\u975e\u6559\u3048\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n
\u4eca\u56de\u3001\u95a2\u4fc2\u3059\u308b\u30bd\u30fc\u30b9\u306f\u4e0b\u8a18\u306b\u8f09\u305b\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n
\u25a0\u691c\u8a3c\u60c5\u5831yaml<\/p>\n
\r\nvalidate:\r\n name:\r\n - validator: RequiredValidator\r\n<\/pre>\n\u25a0ValidationManager<\/p>\n
\r\nclass ValidationManager(object):\r\n VALIDATOR_PACKAGES = [\r\n 'org.fukata.mapshare.system.utils.validation.common.',\r\n 'org.fukata.mapshare.system.utils.validation.extention.',\r\n ]\r\n \r\n valid = None\r\n errors = None\r\n \r\n def __init__(self,validYaml):\r\n self.valid = YamlUtils.load(validYaml)\r\n \r\n def validate(self,model):\r\n # initialize\r\n self.errors = Errors()\r\n \r\n for item in self.valid[config.VALIDATE_KEY]:\r\n for validInfo in self.valid[config.VALIDATE_KEY][item]:\r\n validator = self._getValidatorInstance(validInfo)\r\n # check exists attribute\r\n props = model.properties()\r\n prop = None\r\n if props.has_key(item):\r\n prop = props[item]\r\n else:\r\n # don't have a key.\r\n raise BadKeyError(\"Key %s is don't have property.\" % item)\r\n \r\n value = getattr(model, prop._attr_name(), None)\r\n try:\r\n validator.validate(value, prop, model)\r\n except ValidationError, e:\r\n self.errors.append(prop, e.__str__())\r\n \r\n return not bool(self.errors)\r\n \r\n def _getValidatorInstance(self, validInfo):\r\n\r\n clazz = ReflectionUtils.getClazz(validInfo['validator'], self.VALIDATOR_PACKAGES);\r\n options = validInfo['options'] if validInfo.has_key('options') else {} \r\n return clazz(options)\r\n<\/pre>\n\u25a0ValidationError<\/p>\n
\r\nclass ValidationError(Exception):\r\n def __init__(self, value):\r\n self.value = value\r\n \r\n def __str__(self):\r\n return self.value\r\n<\/pre>\n\u25a0BaseValidator<\/p>\n
\r\nclass BaseValidator(object):\r\n options = None\r\n\r\n def __init__(self, options=None):\r\n self.options = options\r\n \r\n def validate(self,value,prop,model):\r\n return False\r\n<\/pre>\n\u25a0RequiredValidator<\/p>\n
\r\nclass RequiredValidator(BaseValidator):\r\n def validate(self,value,prop,model):\r\n if value is None:\r\n raise ValidationError('Property %s is required' % prop.name)\r\n\r\n if StringUtils.isNone(value):\r\n raise ValidationError('Property %s is required' % prop.name)\r\n \r\n return True\r\n<\/pre>\n\u25a0BaseModel<\/p>\n
\r\n# skip default validation of db.Property\r\nsetattr(db.Property, '__set__', \r\n lambda self, model_instance, value: \r\n setattr(model_instance, self._attr_name(), value))\r\n\r\nclass BaseModel(db.Model):\r\n errors = None\r\n\r\n def __init__(self, *args, **kwds):\r\n super(BaseModel, self).__init__(*args, **kwds)\r\n self.errors = Errors()\r\n\r\n def validate(self,valid_yaml=None):\r\n if valid_yaml is None:\r\n for prop in self.properties().values():\r\n value = getattr(self, prop._attr_name(), None)\r\n try:\r\n value = prop.validate(value)\r\n setattr(self, prop._attr_name(), value)\r\n except db.BadValueError, e:\r\n self.errors.append(prop, e.message)\r\n return not bool(self.errors)\r\n else:\r\n manager = ValidationManager(valid_yaml)\r\n manager.validate(self)\r\n self.errors = manager.errors\r\n return not bool(self.errors)\r\n<\/pre>\n\u25a0Errors<\/p>\n
\r\nclass Errors(list):\r\n '''container of validation errors\r\n '''\r\n def __init__(self):\r\n self.map = dict()\r\n\r\n def append(self, prop, msg=None, error=True):\r\n if error:\r\n if isinstance(prop, db.Property):\r\n super(Errors, self).append(Error(prop, msg))\r\n self.map[prop.name] = len(self) - 1\r\n elif isinstance(prop, (str, unicode)):\r\n super(Errors, self).append(Error(prop, msg))\r\n self.map[prop] = len(self) - 1\r\n else:\r\n super(Errors, self).append(Error(None, prop))\r\n\r\n def clear(self):\r\n del self[:]\r\n \r\n def get(self, index, default=None):\r\n return self[index] if index in self else default\r\n\r\n def tostr(self, sep=u\"\\n\", **ops):\r\n msgs=list()\r\n for error in self:\r\n msgs.append(error.tostr(**ops))\r\n return sep.join(msgs)\r\n\r\n def __str__(self):\r\n return self.tostr()\r\n\r\n def __contains__(self, name):\r\n return name in self.map\r\n \r\n def __getitem__(self, index):\r\n if isinstance(index, (str, unicode)):\r\n if index not in self.map:\r\n raise IndexError(u\"'%s' property has not error.\" % index)\r\n index = self.map[index]\r\n return super(Errors, self).__getitem__(index)\r\n<\/pre>\n\u25a0Error<\/p>\n
\r\nclass Error(object):\r\n '''container of validation error\r\n '''\r\n \r\n def __init__(self, prop, msg=None):\r\n self.prop = prop\r\n self.msg = msg\r\n\r\n def __str__(self):\r\n return self.tostr()\r\n\r\n def tostr(self, format=u\"%(msg)s\"):\r\n if isinstance(self.prop, db.Property) and format:\r\n name = self.prop.verbose_name or self.prop.name\r\n msg = re.sub(' '+name+' ', ' %(name)s ', self.msg)\r\n format = format % {\r\n 'msg': msg,\r\n }\r\n return _(format) % {\r\n 'name': _(self.prop.verbose_name) or _(self.prop.name),\r\n }\r\n else:\r\n return _(self.msg)\r\n<\/pre>\n\u25a0ReflectionUtils<\/p>\n
\r\nclass ReflectionUtils(object):\r\n BIG_PATTERN = re.compile('[A-Z]')\r\n \r\n @classmethod\r\n def getClazz(cls,className,basePackageList=[]):\r\n packageName = cls.generatePackageName(className)\r\n \r\n clazz = None\r\n if len(basePackageList)>0:\r\n for basePackage in basePackageList:\r\n packageName = basePackage+packageName\r\n try:\r\n module = __import__(packageName, globals(), locals(), [className])\r\n clazz = getattr(module, className)\r\n except ImportError, e:\r\n continue\r\n except AttributeError, e:\r\n continue\r\n else:\r\n try:\r\n module = __import__(packageName, globals(), locals(), [className])\r\n clazz = getattr(module, className)\r\n except ImportError, e:\r\n pass\r\n except AttributeError, e:\r\n pass\r\n \r\n if clazz is None:\r\n raise AttributeError('%s class is not exists.' % className)\r\n \r\n return clazz\r\n \r\n \r\n @classmethod\r\n def newInstance(cls,className,basePackageList=[]):\r\n try:\r\n clazz = cls.getClazz(className, basePackageList)\r\n instance = clazz()\r\n except ImportError, e:\r\n pass\r\n except AttributeError, e:\r\n pass\r\n \r\n if instance is None:\r\n raise AttributeError('%s is not exists.' % className)\r\n \r\n return instance\r\n \r\n @classmethod\r\n def generatePackageName(cls,className):\r\n split = cls.BIG_PATTERN.split(className)\r\n findall = cls.BIG_PATTERN.findall(className)\r\n \r\n str_list = []\r\n white=0\r\n for i in range(len(split)):\r\n if split[i]:\r\n head = findall[i-white].lower()\r\n str = head+split[i]\r\n str_list.append(str)\r\n else:\r\n white = white+1\r\n \r\n return '_'.join(str_list)\r\n<\/pre>\n\u25a0YamlUtils<\/p>\n
\r\nclass YamlUtils(object):\r\n \r\n @classmethod\r\n def load(cls,path):\r\n return yaml.load(cls._get_stream(path))\r\n \r\n @classmethod\r\n def load_all(cls,path):\r\n return yaml.load_all(cls._get_stream(path))\r\n \r\n @classmethod\r\n def _get_stream(cls,path):\r\n fp = open(path, 'r')\r\n stream = fp.read()\r\n fp.close()\r\n return stream\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"GAE\u3067\u30a2\u30d7\u30ea\u3092\u4f5c\u6210\u3057\u3066\u3044\u3066\u3001\u5165\u529b\u5024\u3078\u306e\u691c\u8a3c\u6a5f\u69cb\u304c\u8ca7\u5f31\u3060\u3068\u601d\u3063\u305f\u306e\u3067\u3001\u4f5c\u308a\u307e\u3057\u305f\u3002\u4eca\u56de\u4f5c\u6210\u3057\u305f\u306e\u306f\u3001\u691c\u8a3c\u60c5\u5831\u3092yaml\u306b\u8a18\u8ff0\u3057\u3001\u305d\u306e\u691c\u8a3c\u60c5\u5831\u306b\u6cbf\u3063\u3066\u30e2\u30c7\u30eb\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u8d70\u67fb\u3057\u3066\u3044\u304f\u3068\u3044\u3046\u7269\u3067\u3059\u3002 \u691c\u8a3c … \u7d9a\u304d\u3092\u8aad\u3080<\/a><\/p>\n","protected":false},"author":2,"featured_media":9223372036854775807,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1980],"tags":[403,404,410],"_links":{"self":[{"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/posts\/1887"}],"collection":[{"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/comments?post=1887"}],"version-history":[{"count":0,"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/posts\/1887\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/media\/9223372036854775807"}],"wp:attachment":[{"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/media?parent=1887"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/categories?post=1887"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.fukata.org\/wp-json\/wp\/v2\/tags?post=1887"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}