Dynamically attach properties to an instance of ndb.Model and have them in the to_dict() representation
我正在通过 Google App Engine NDB 编写一个 REST api
我排除了现有库,因为我需要控制事务和缓存。
出于类似的原因,我排除了 Google Endpoints,也因为我不想使用他们提供的 javascript 客户端。
在评估架构决策时,我遇到了一些问题和奇怪的情况,这是因为我对 python 和 pythonic 风格的经验可能不够丰富。
在这一刻,我试图提出一些应该塑造我的代码库的指导方针:
-
在 Handlers -> 创建对象的字典表示
并将它们作为 json 返回;执行身份验证和授权
支票 - 将ndb交互封装在Services中
- 模型类总是接收模型对象或键作为参数并返回模型对象或模型列表
- 模型类被导入并在服务中使用
我遇到的一件特别的事情是
我使用映射模型实现了多对多关系,例如
UserOrganizationMembership,具有 User 和 Organization
的密钥
现在,在我的服务中,有时我想返回一个对象,其中包含当前用户所属的组织列表,并递归地获取每个组织中的公司:
1 2 3 4 5 6 7 8 9 | 'organizations': [ { 'name': 'TEST' 'companies': [ {company1}, {company2}] }, { ... } ] |
我这样做
1 2 3 4 5 6 7 | 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] |
在突出显示的行中,我将动态属性 \\'companies\\' 附加到组织模型
现在,如果我在处理程序中调用此方法,当我创建字典表示以输出 json 时,ndb.Model.to_dict() 实现会忽略动态附加的属性。
我尝试过的一个解决方案是(在我的处理程序中)
1 2 3 4 | 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() |
但我不喜欢它,因为我需要知道每个组织都有一个\\'companies\\'属性,而且代码看起来有点复杂而且不明显
另一种方法是覆盖 ndb.Model.to_dict()
隔离动态附加属性并提供字典表示,这简化了我在处理程序中的代码,让我只对服务返回的内容调用 to_dict()。
从 google.appengine.ext 导入 ndb
导入实用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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) |
您对这种方法有什么建议吗?任何想法将不胜感激!
ndb 通过 Expando 类型支持动态属性。
而不是将模型定义为:
1 | class BaseModel(ndb.Model): |
使用
定义它
1 | class BaseModel(ndb.Expando): |
现在,如果你写