Python 在NDB中存储关系值的有效方法
我有这个数据模型(我做的,所以如果有更好的方法,请告诉我)。 我有一个Python 在NDB中存储关系值的有效方法,python,google-app-engine,google-cloud-datastore,app-engine-ndb,Python,Google App Engine,Google Cloud Datastore,App Engine Ndb,我有这个数据模型(我做的,所以如果有更好的方法,请告诉我)。 我有一个俱乐部,可以有很多课程。现在我想知道俱乐部的所有会员和教练成员和讲师存储在课程模型中,俱乐部对他们有一个引用。 请参阅代码 class Course(ndb.Model): ... instructor_keys = ndb.KeyProperty(kind="User", repeated=True) member_keys = ndb.KeyProperty(kind="User", repeate
俱乐部
,可以有很多课程
。现在我想知道俱乐部的所有会员
和教练
<代码>成员和讲师
存储在课程
模型中,俱乐部
对他们有一个引用。
请参阅代码
class Course(ndb.Model):
...
instructor_keys = ndb.KeyProperty(kind="User", repeated=True)
member_keys = ndb.KeyProperty(kind="User", repeated=True)
@property
def instructors(self):
return ndb.get_multi(self.instructor_keys)
@property
def members(self):
return filter(lambda x: x.is_active, ndb.get_multi(self.member_keys))
def add_instructor(self, instructor):
if instructor.key not in self.instructor_keys:
self.instructor_keys.append(instructor.key)
self.put()
def rm_instructor(self, instructor):
if instructor.key in self.instructor_keys:
self.instructor_keys.remove(instructor.key)
self.put()
def add_member(self, member):
if member.key not in self.member_keys:
self.member_keys.append(member.key)
self.put()
def rm_member(self, member):
if member.key in self.member_keys:
self.member_keys.remove(member.key)
self.put()
及
现在,课程
上的@属性
对我来说似乎没问题。(我说得对吗?)
但是俱乐部中的那家似乎效率很低。每次我都要迭代所有课程
来计算成员
和培训师
。此外,这些方法不是缓存的,而是每次计算的。因此,如果这是非常昂贵的
有什么建议吗?
我想让讲师
和会员
作为俱乐部
的一个关键列表,并在每次我向课程
添加学员时更新俱乐部,但不确定这是否正确
PS:是否有更好的方法在ndb上执行过滤器。获取多个?我会尝试规范化您的模型,而不是使用非规范化模型:
class CourseInscription(ndb.Model):
member = ndb.KeyProperty(kind='User', required=True)
course = ndb.KeyProperty(kind='Course', required=True)
is_active = ndb.BooleanProperty(default=True)
然后,您可以添加如下内容
class Course(ndb.Model):
# all the stuff already there
@property
def members(self):
return CourseInscription.query(CourseInscription.course == self.key)
一般来说,我更喜欢只返回查询,让调用方决定直接调用它,或者添加一些过滤/排序,而不是直接执行ndb.get\u
我通常做的另一个很好的操作是使用关系实体的父对象来构造它们的id,这样我就可以用一个get-by-id轻松地检查它们是否存在,而不必进行查询
class CourseInscription(ndb.Model):
# all the other stuff
@staticmethod
def build_id(user_key, course_key):
return '%s/%s' % (user_key.urlsafe(), course_key.urlsafe())
# somewhere I can create an inscription like
CourseInscription(
id=CourseInscription.build_id(user_key, course_key),
user=user_key, course=course_key, is_active=True
).put()
# somewhere else I can check if a User is in a Course by just getting... no queries needed
if ndb.Key(CourseInscription, CourseInscription.build_id(user, course)).get():
# Then the user is in the course!
else:
# then it's not
除了被课程引用之外,会员和讲师加入俱乐部也是非常有意义的。考虑使用案例,会员需要在加入俱乐部提供的课程之前加入俱乐部(当然,这可能同时发生)。直接(在俱乐部中)引用会员/讲师也比每次都要遍历课程要有效得多。您的折衷办法是额外的代码维护,但在这种情况下,这似乎是合理的
关于活动课程过滤器,您可能希望考虑一个“活动”课程列表和一个“不活动”的课程列表:一旦课程不再提供,将其移到“不活动”列表中(并将其从“活动”列表中删除)。谢谢您的建议,您是正确的成员名单。谢谢。我不确定在NDB中使用规范化,以及它是否是正确的方法。我同意你的意见,我应该回答你的问题。但是
self.member\u keys
是一个键列表,在这种情况下我应该返回什么?def build\u id(user\u key,course\u key):
还自动设置与该值相关的id?或者它是如何在put上工作的?我修复了build_id示例,以显示它在创作中的使用(以及在铭文类中,而不是在课程中),除了品味之外。。。以下是Guido关于使用重复属性和~1000限制的回复:我认为限制不是一个很难的限制,而是在使用此类属性时需要考虑的限制。请记住,索引的是列表中每个元素的一条记录(因此,如果在同一实体中有多个重复属性,它会快速爆炸)。IMHO,重复属性不应用于一对多,而应仅用于一对一些(实际一对多关系应规范化)或实际(有限)值,而不是关系
class CourseInscription(ndb.Model):
# all the other stuff
@staticmethod
def build_id(user_key, course_key):
return '%s/%s' % (user_key.urlsafe(), course_key.urlsafe())
# somewhere I can create an inscription like
CourseInscription(
id=CourseInscription.build_id(user_key, course_key),
user=user_key, course=course_key, is_active=True
).put()
# somewhere else I can check if a User is in a Course by just getting... no queries needed
if ndb.Key(CourseInscription, CourseInscription.build_id(user, course)).get():
# Then the user is in the course!
else:
# then it's not