【问题标题】:Understanding ndb key class vs KeyProperty了解 ndb 密钥类与 KeyProperty
【发布时间】:2023-03-24 11:59:01
【问题描述】:

我浏览了文档、文档和 SO 问题和答案,但仍在努力理解其中的一小部分。您应该选择哪个以及何时?

这是我目前读到的内容(只是示例):

关键类对我来说似乎很简单。当您创建 ndb 实体时,数据存储区会自动为您创建一个密钥,该密钥通常以 key(Kind, id) 的形式为您创建 id。

假设你有这两个模型:

class Blah(ndb.Model):
     last_name = ndb.StringProperty()

class Blah2(ndb.Model):
     first_name = ndb.StringProperty()
     blahkey = ndb.KeyProperty()

因此,只需使用密钥类型,您就想让 Blah1 成为父母(或有几个姓氏相同的家庭成员)

lname = Blah(last_name = "Bonaparte")
l_key = lname.put() **OR**
l_key = lname.key.id() # spits out some long id 

fname_key = l_key **OR**
fname_key = ndb.Key('Blah', lname.last_name) # which is more readable.. 

然后:

lname = Blah2( parent=fname_key, first_name = "Napoleon")
lname.put()

lname2 = Blah2( parent=fname_key, first_name = "Lucien")
lname2.put()

到目前为止一切顺利(我认为)。现在关于 Blah2 的 KeyProperty。假设 Blah1 仍然相同。

lname3 = Blah2( first_name = "Louis", blahkey = fname_key)
lname3.put()

这样对吗?

如何查询各种东西

查询姓氏:

Blah.query() # all last names
Blah.query(last_name='Bonaparte') # That specific entity.

名字:

Blah2.query()
napol =   Blah2.query(first_name = "Napoleon")
bonakey = napol.key.parent().get() # returns Bonaparte's key ??

bona = bonakey.get() # I think this might be redundant

这就是我迷路的地方。如何使用 key 或 keyproperty 从名字中查找 Bonaparte。我没有在这里添加它,也许应该添加它,这是关于父母、祖父母、曾祖父母的讨论,因为 Keys 跟踪祖先/父母。

您将如何以及为什么使用 KeyProperty 与固有密钥类。还假设您有 3 个传感器 s1、s2、s3。每个传感器都有数千个读数,但您希望保持与 s1 相关联的读数,以便您可以绘制 s1 今天的所有读数。你会用哪个? KeyProperty 还是密钥类?如果这已在其他地方得到解答,我深表歉意,但我没有看到关于选择哪个以及为什么/如何选择的明确示例/指南。

【问题讨论】:

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


    【解决方案1】:

    我认为混乱来自使用密钥。 Key 不与实体内部的任何属性相关联,它只是定位单个实体的唯一标识符。可以是数字也可以是字符串。

    幸运的是,除了这一行之外,您的所有代码看起来都不错:

    fname_key = ndb.Key('Blah', lname.last_name) # which is more readable.. 
    

    构造一个 Key 需要一个唯一的 ID,这与属性不同。也就是说,它不会将变量lname.last_name 与属性last_name 相关联。相反,您可以像这样创建记录:

    lname = Blah(id = "Bonaparte")
    lname.put()
    lname_key = ndb.Key('Blah', "Bonaparte")
    

    保证您只有一个具有该 ID 的 Blah 实体。实际上,如果使用像 last_name 这样的字符串作为 ID,则不需要将其存储为单独的属性。将实体 ID 视为唯一的额外字符串属性。

    接下来,请注意不要假设 Blah.last_name 和 Blah2.first_name 在您的查询中是唯一的:

    lname = Blah2( parent=fname_key, first_name = "Napoleon")
    lname.put()
    

    如果您多次这样做,将会有多个名字为 Napoleon 的实体(都具有相同的父键)。

    继续上面的代码:

    napol =   Blah2.query(first_name = "Napoleon")
    bonakey = napol.key.parent().get() # returns Bonaparte's key ??
    bona = bonakey.get() # I think this might be redundant
    

    napol 保存查询,而不是结果。您需要致电napol.fetch() 以获取所有带有“Napolean”的实体(或napol.get(),如果您确定只有一个实体)。 bonakey 正好相反,它持有父实体,因为 get() 而不是 Bonaparte 的密钥。如果您将 .get() 关闭,则 bona 将正确地拥有父级。

    最后,关于传感器的问题。您可能不需要 KeyProperty 或“固有”键。如果你有这样的阅读课:

    class Readings(ndb.Model):
        sensor = ndb.StringProperty()
        reading = ndb.IntegerProperty()
    

    然后您可以将它们全部存储在一个没有键的表中。 (您可能希望包含时间戳或其他属性。)稍后,您可以使用以下查询检索:

    s1_readings = Readings.query(Readings.sensor == 'S1').fetch()
    

    【讨论】:

      【解决方案2】:

      我也是 NDB 的新手,我现在还没有完全理解,但我认为当您使用 Napoleon 的父级创建 Blah2 时,您将需要父母查询它或不会出现。例如:

      napol = Blah2.query(first_name = "Napoleon")
      

      不会得到任何东西(并且您没有为 NDB 使用正确的格式),但使用父级就可以了:

      napol = Blah2.query(ancestor=fname_key).filter(Blah2.first_name == "Napoleon").get
      

      不知道这是否为您的问题提供了一些启示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-04
        相关资源
        最近更新 更多