在 NDB 中存储关系值的有效方法 [英] Efficient way to store relation values in NDB
问题描述
我有这个数据模型(我制作了它,所以如果有更好的方法,请告诉我).基本上我有Club
,可以有很多Courses
.现在我想知道一个俱乐部的所有members
和instructors
.members
和 instructors
存储在 Course
模型中,并且 Club
有对它们的引用.看代码..
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()
和
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))
现在,Course
上的 @property
对我来说似乎没问题.(我对吗?)但是 Club
中的那个似乎非常低效.每次我必须迭代所有 Courses
以计算 members
和 trainers
.此外,这些方法不会被缓存,而是每次都会计算.所以如果它非常昂贵.
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.
有什么建议吗?我正在考虑将 instructors
和 members
作为密钥列表也在 Club
中,并且每次我将某人添加到 Club 时更新俱乐部code>Course
,但不确定它是否正确.
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:有没有更好的方法在 ndb.get_multi
上也做 filter
?
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)
一般来说,我更喜欢只返回查询并让调用者决定直接调用它或添加更多过滤/排序而不是直接执行 ndb.get_multi.
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.
我通常做的另一个不错的事情是使用它们的父级为关系实体构造 id,这样我就可以轻松地使用 get by id 来检查是否存在,而不必查询
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屋!