【问题标题】:App Engine editing an instance in a repeated KeyProperty via the instance itselfApp Engine 通过实例本身在重复的 KeyProperty 中编辑实例
【发布时间】:2015-11-25 11:17:27
【问题描述】:

假设我有以下模型:

class Author(ndb.Model)
    books = ndb.KeyProperty(kind='Book', repeated=True)

class Book(ndb.Model)
    title = ndb.StringProperty()

因此,在某个时候,您将拥有一个作者,其中包含n 书籍的列表。

问题: 当我编辑一本书时,如何在不提及“当前”作者的情况下更改作者?我是否需要在Book 上添加与KeyProperty 的反向关系?

更改作者时,我必须从旧作者列表中删除该书并将其添加到新作者列表中。感觉有点麻烦。有没有更好的办法?

额外问题:如果一本书被删除了怎么办?在作者的书单中会有一个None 值。我必须删除它吗?

注意:我使用的是重复的 KeyProperty,因为这使得订购书籍变得容易,这对我来说很重要。

【问题讨论】:

    标签: google-app-engine google-cloud-datastore app-engine-ndb google-app-engine-python


    【解决方案1】:

    当我编辑一本书时,如何在不提及“当前”作者的情况下更改作者?

    您可以在保存实体之前使用ndb.Model.allocate_ids 保留密钥

    我是否需要在 Book 上添加与 KeyProperty 的反向关系?

    根据您的模型,添加反向查找键可以让您的生活更轻松

    如果一本书被删除了怎么办?作者的书单中会有一个 None 值。我必须删除它吗?

    Auther.books 中的键在这种情况下不会自动变为 null。您必须自己删除它。

    我正在使用重复的 KeyProperty,因为这使得订购书籍变得容易,这对我来说很重要。

    一个潜在的问题是实体的大小限制为 1mb。如果作者是多产的作家(例如 Edwy Searles Brooks 已发表 800 多部作品),则可能会超出限制。

    我会这样设计模型:

    class Author(ndb.Model):
        name = ndb.StringProperty()
    
    class Book(ndb.Model):
        authors = ndb.KeyProperty('Author', required=True)  # Usually it is at most a couple of authors  
        title = ndb.StringProperty()
    

    要查找由 id 为 1234 的特定作者撰写的所有书籍,您可以

      Book.query(Book.authors == ndb.Key('Author', 1234)).fetch()
    

    显然书籍的排序必须明确存储,我建议第三方实体跟踪此信息:

    class BookList(ndb.Model):
      name = ndb.StringProperty()
      book_keys = ndb.KeyProperty(kind='Book', repeated=True)
    

    那么你就可以用这种方式取书了

    stephen_king_book_list = stephen_king_book_list_key.get()
    books = ndb.get_multi(stephen_king_book_list.book_keys)
    # Some of key can lead to None if the underlying book is already deleted
    # You can define some background job to sweep clean the list from time to time 
    # But let filter out the bad guys first 
    books = [b for b in books if b]  
    

    如果您认为您的列表会非常长,您可以将列表分解为链表结构等片段

    class BookList(ndb.Model):
      prev_segment = ndb.KeyProperty(kind='BookList', required=False)
      next_segment = ndb.KeyProperty(kind='BookList', required=False)
      name = ndb.StringProperty()
      book_keys = ndb.KeyProperty(kind='Book', repeated=True)
    

    您可以通过以下方式轻松找到第一个片段:

      starting_point = BookList.query(BookList.name == 'Stephen_King',
         BookList.prev_segment == None
      ).fetch()
    

    当然,如果插入非常频繁,您可能希望使用另一种结构来保存图书列表

    【讨论】:

    • 感谢您的回答。也许我的 Book/Author 示例不适合我的用例。如前所述,顺序非常重要。将其视为演示/幻灯片关系。我也更喜欢您的设计建议,但是您将如何处理演示文稿中幻灯片的顺序?或书籍作者列表中的书籍。
    • 使用order by cloud.google.com/appengine/docs/python/datastore/… 使用book 示例,您可以按照publication_date 等某些条件对结果进行排序
    • 顺序应该是可控的:一本书应该可以在作者的书单中上下移动。这可以通过sort_value 属性来实现。但是,当您想移动一本书(通过更改sort_value)时,您必须为所有作者的书籍更新sort_value,这需要对每本书进行查询吗?
    • 我会建议某种music playlist 之类的构造来跟踪排序。您只需要注意实体的 1Mb 限制。我会更新答案以反映这一点
    【解决方案2】:

    你们的关系真的是走错路了。您应该在 Book 上有一个指向 Author 的 KeyProperty;那么如果你想查询一个作者的所有书籍,你可以查询作者键。

    【讨论】:

    • 感谢您的回答。你能看看安东尼回答下面的cmets吗?顺序非常重要,这就是我以这种方式建模的原因。所以我可以利用重复键属性中的顺序,这是一个列表。
    猜你喜欢
    • 1970-01-01
    • 2011-07-01
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 2012-02-21
    • 1970-01-01
    相关资源
    最近更新 更多