将关系值存储在NDB中的有效方法 [英] Efficient way to store relation values in NDB

查看:98
本文介绍了将关系值存储在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>。此外,这些方法不会被缓存,而是每次计算。所以如果它非常昂贵。

任何建议?
我正在考虑将教师成员作为< Club
,并在每次向课程添加某人时更新分会,但不确定是否正确。



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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆