将关系值存储在NDB中的有效方法 [英] Efficient way to store relation values in NDB
问题描述
我有这个数据模型(我是这么做的,所以如果有更好的方法来做,请告诉我)。
基本上我有 Club
,可以有许多课程
。现在我想知道俱乐部的所有成员
和教练
。 成员
和教师
存储在课程
模型中, 俱乐部
有一个对他们的引用。
查看代码..
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):
如果instructor.key不在self.instructor_keys中:
self。 instructor_keys.append(instructor.key)
self.put()
def rm_instructor(self,instructor):
self.instructor_keys中的instructor.key:
self.instructor_keys.remove(instructor.key)
self.put()
$ b $ def add_member(self,member):
如果member.key不在self.member_keys中:
self.member_key s.append(member.key)
self.put()
$ b $ def rm_member(self,member):
self.member_keys中的member.key:
self.member_keys.remove(member.key)
self.put()
和
class Club(ndb.Model):
...
owner_keys = ndb.KeyProperty(kind = 用户,重复=真)
course_keys = ndb.KeyProperty(kind =Course,repeated = True)
$ property
def members(self ):
#TODO:这是正确的吗?有效?
l_members = []
for self.courses中的课程:
_members = l_members + courses.members
return l_members
@property
def trainers(self):
l_trainers = []
for self courses:
l_trainers = l_trainers + courses.trainers
return l_trainers
@特性
def所有者(self):
返回ndb.get_multi(self.owners_keys)
@property
def courses(self):
return过滤器(lambda x:x.is_active,ndb.get_multi(self.course_keys))
def add_owner(self,owner):
如果owner.key不在self.owners_keys中:
self.owner_keys.append(owner.key)
self.put()
$ b $ def rm_owner(self,owner):
self.owners_keys中的owner.key:
self.owner_keys.remove(owner.key)
self.put()
def add_course(self,course):
如果course.key不在self.courses_keys中:
self.course_keys.append(course.key)
self.put()
def rm_course(self,course ):
如果self.courses_keys中的course.key:
self.course_keys.remove(course.key)
self.put()
def membership_type(self ,user):
如果user.key在self.owners_keys中:
返回OWNER
elif self.members中的用户:
返回MEMBER
elif用户在self.trainers中:
返回TRAINER
else:
异常(用户%s不在俱乐部%s中%(user.id,self.id))
现在, 任何建议? @property
code>课程对我来说似乎没问题。 (对吗?)
,但是 Club
中的那个似乎效率很低。我每次迭代所有课程
来计算成员
和训练师 code>。此外,这些方法不会被缓存,而是每次计算。所以如果它非常昂贵。
,并在每次向
我正在考虑将教师
和成员
作为<课程
添加某人时更新分会,但不确定是否正确。
PS:在 ndb.get_multi
上还有更好的方法来做过滤器
?
我试图规范化你的模型,而不是去规范化一个:
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):
#所有的东西已经存在
@property
def members(self):
return CourseInscription.query(CourseInscription.c ourse == self.key)
一般而言,我宁愿只返回查询并让调用者决定直接调用它,或直接添加一些过滤/排序,而不是直接执行 ndb.get_multi 。
我通常做的另一个很好的触摸是使用他们的父母为关系实体构造id,所以我可以轻松地通过id来检查存在,而不必查询
class CourseInscription(ndb.Model):
#所有其他的东西
@staticmethod
def build_id(user_key,course_key):
return'%s /%s'%(user_key.urlsafe(),course_key.urlsafe())
#某处我可以创建一个题目,如
CourseInscription(
id = CourseInscription.build_id(user_key,course_key),
user = user_key,course = course_key,is_active = True
).put()
$ b $其他地方我可以检查用户在课程中,只需...不需要查询ed
如果ndb.Key(CourseInscription,CourseInscription.build_id(user,course))。get():
#那么用户在进程中!
else:
#那么它不是
I've this data model (I made it, so if there's a better way to do it, please let me know).
Baically I've Club
that can have many Courses
. now I want to know all the members
and instructors
of a Club. members
and instructors
are stored in the Course
model, and Club
has a reference to them.
See the code..
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()
and
class Club(ndb.Model):
...
owners_keys = ndb.KeyProperty(kind="User", repeated=True)
course_keys = ndb.KeyProperty(kind="Course", repeated=True)
@property
def members(self):
# TODO: is this correct? efficient?
l_members = []
for courses in self.courses:
l_members = l_members + courses.members
return l_members
@property
def trainers(self):
l_trainers = []
for courses in self.courses:
l_trainers = l_trainers + courses.trainers
return l_trainers
@property
def owners(self):
return ndb.get_multi(self.owners_keys)
@property
def courses(self):
return filter(lambda x: x.is_active, ndb.get_multi(self.course_keys))
def add_owner(self, owner):
if owner.key not in self.owners_keys:
self.owner_keys.append(owner.key)
self.put()
def rm_owner(self, owner):
if owner.key in self.owners_keys:
self.owner_keys.remove(owner.key)
self.put()
def add_course(self, course):
if course.key not in self.courses_keys:
self.course_keys.append(course.key)
self.put()
def rm_course(self, course):
if course.key in self.courses_keys:
self.course_keys.remove(course.key)
self.put()
def membership_type(self, user):
if user.key in self.owners_keys:
return "OWNER"
elif user in self.members:
return "MEMBER"
elif user in self.trainers:
return "TRAINER"
else:
raise Exception("The user %s is not in the club %s" % (user.id, self.id))
Now, the @property
on the Course
seems to be ok to me. (am I right?)
but the one in the Club
seems to be very inefficient. every time i've to iterate all the Courses
to compute the members
and trainers
. Plus these methods are not cached but computed every time. So if it's very costly.
Any suggestion?
I was thinking about having instructors
and members
as a list of key also in Club
, and update the club every time I add someone to the Course
, but not sure it's correct.
PS: Is there a better way to do also the filter
on a ndb.get_multi
?
I'd try to normalize your model instead of going for a de-normalized one:
class CourseInscription(ndb.Model):
member = ndb.KeyProperty(kind='User', required=True)
course = ndb.KeyProperty(kind='Course', required=True)
is_active = ndb.BooleanProperty(default=True)
Then, you can just add something like
class Course(ndb.Model):
# all the stuff already there
@property
def members(self):
return CourseInscription.query(CourseInscription.course == self.key)
In general, I prefer to just return the query and let the caller decide to even call it directly or add some more filtering/sorting instead of doing ndb.get_multi directly.
Another nice touch I usually do is to construct the id for the relational entities using their parents, so I can easily check for existence with a get by id instead of having to query
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中的有效方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!