from google.appengine.ext import db
#db.Propertyを変更して、規定のバリデーションをスキップする
setattr(db.Property, '__set__',
lambda self, model_instance, value:
setattr(model_instance, self._attr_name(), value))
#バリデーション機能を追加したベースモデル
class BaseModel(db.Model):
errors = None
def __init__(self, *args, **kwds):
super(BaseModel, self).__init__(*args, **kwds)
self.errors = Errors()
def validate(self):
for prop in self.properties().values():
value = getattr(self, prop._attr_name(), None)
try:
value = prop.validate(value)
setattr(self, prop._attr_name(), value)
except db.BadValueError, e:
self.errors.append(prop, e.message)
return not bool(self.errors)
is_valid = property(lambda self: self.validate())
#バリデーションエラーを保存するコンテナ
class Error(object):
def __init__(self, prop, msg=None):
self.prop = prop
self.msg = msg
def __str__(self):
return self.tostr()
def tostr(self, format=u"[%s] %s"):
if isinstance(self.prop, db.Property) and format:
return format % (self.prop.verbose_name
or self.prop.name, self.msg)
else:
return self.msg
#エラーの集合を扱うコンテナ
class Errors(list):
def __init__(self):
self.map = dict()
def append(self, prop, msg=None, error=True):
if error:
if isinstance(prop, db.Property):
super(Errors, self).append(Error(prop, msg))
self.map[prop.name] = len(self) - 1
elif isinstance(prop, (str, unicode)):
super(Errors, self).append(Error(prop, msg))
self.map[prop] = len(self) - 1
else:
super(Errors, self).append(Error(None, prop))
def clear(self):
del self[:]
def get(self, name, default=None):
return self[name] if name in self else default
def tostr(self, sep=u"n", **ops):
msgs=list()
for error in self:
msgs.append(error.tostr(**ops))
return sep.join(msgs)
def __str__(self):
return self.tostr()
def __contains__(self, name):
return name in self.map
def __getitem__(self, index):
if isinstance(index, (str, unicode)):
if index not in self.map:
raise IndexError(u"'%s' property has not error." % index)
index = self.map[index]
return super(Errors, self).__getitem__(index)