我正在通过Google App Engine NDB编写REST api
我排除了现有的库,因为我需要控制事务和缓存。 我出于类似原因排除了Google端点,也因为我不想使用他们提供的javascript客户端。
在评估架构决策时,我遇到了一些问题和奇怪的情况,这是因为我对python和pythonic风格的体验可能不够大。
在这一刻我试图提出一些应该塑造我的代码库的指南:
我遇到的一件特别的事就是这个 我有一个多对多的关系,我用映射模型实现,类似于 UserOrganizationMembership ,具有用户和组织的密钥
现在,在我的服务中,在某些时候我想返回一个对象,该对象包含当前用户所属组织的列表,并递归地获取每个组织中的公司:
'organizations': [
{
'name': 'TEST'
'companies': [ {company1}, {company2}]
},
{
...
}
]
我这样做
def user_organizatios_with_companies(user):
def fetch_companies(x):
x.companies = Company.by_organization(x) #NOTICE THIS
return x
user_organizations = [ membership.organization.get() for membership in UserOrganizationMembership.by_user(user)]
return [fetch_companies(x) for x in user_organizations]
在突出显示的行我将动态属性'公司'附加到组织模型
现在,如果我在Handler中调用此方法,当我创建字典表示以输出json时, ndb.Model.to_dict()实现会忽略动态附加属性。
我试过的一个解决方案是(在我的处理程序中)
xs = Service.user_organizatios_with_companies(u)
organizations = [x.to_dict() for x in xs]
for x in xrange(0,len(xs)):
organizations[x]['companies'] = xs[x].to_dict()
但我不喜欢因为我需要知道每个组织都有'公司'属性,而且代码看起来有点复杂而且不明显
另一种方法是覆盖ndb.Model.to_dict() 隔离动态附加属性并提供字典表示,这简化了我在Handler中的代码,让我只对服务返回的内容调用to_dict()。
来自google.appengine.ext导入ndb import util
class BaseModel(ndb.Model):
created = ndb.DateTimeProperty(auto_now_add = True)
updated = ndb.DateTimeProperty(auto_now = True)
# App Engine clock times are always
# expressed in coordinated universal time (UTC).s
def to_dict(self, include=None, exclude=None):
result = super(BaseModel,self).to_dict(include=include, exclude=exclude)
result['key'] = self.key.id() #get the key as a string
# add properties dynamically added to the class
dynamic_vars = {k:v for (k,v) in vars(self).iteritems() if not k.startswith('_')}
for prop, val in dynamic_vars.iteritems():
result[prop] = val.to_dict() if not isinstance(val, list) else [x.to_dict() for x in val]
return util.model_db_to_object(result)
您对这种方法有什么建议吗?任何想法都将受到赞赏!
答案 0 :(得分:1)
ndb通过Expando type支持动态属性。
而不是将模型定义为:
class BaseModel(ndb.Model):
使用Expando
定义它:
class BaseModel(ndb.Expando):
现在,如果你写x.companies = [...]
,调用_to_dict()将输出这些公司。在put()
这些实体时要小心,因为任何动态添加的属性也会被放入数据存储区。