理解ndb key类与KeyProperty的区别

6
我已经查阅了文档、文献和stackoverflow上的问题和答案,但仍然难以理解其中的一个小部分。在何时应该选择哪个呢?
到目前为止,这是我所读过的(只是样例):
- ndb documentation - movie database structure on SO - Parent Key issues 对我来说,关键类似乎很简单。当您创建一个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

这是我迷失的地方。如何使用键或键属性通过名字查找Bonaparte。我没有在此处添加它,也许应该,那就是关于父母、祖父母、曾祖父母的讨论,因为键跟踪先辈/父母。
如何以及为什么要使用KeyProperty而不是固有的key类。另外,想象一下你有3个传感器s1、s2、s3。每个传感器都有成千上万次的读数,但你想保持与s1相关的读数,这样你就可以绘制出今天s1的所有读数。你会使用哪一个?KeyProperty还是key类?如果已经在其他地方回答了这个问题,我很抱歉,但我没有看到关于选择哪种方法以及为什么/如何的清晰示例/指南。
2个回答

3

我想混淆的原因是使用了键。键与实体内任何属性都没有关联,它只是用于定位单个实体的唯一标识符。它可以是数字或字符串。

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

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

构建一个键需要一个唯一标识符,它与属性不同。也就是说,它不会将变量 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或“内在”的键。如果你有一个像这样的Readings类:

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

如果您需要将它们全部存储在单个不带键的表中,那么可以这样做。(您可能需要包括时间戳或其他属性。)稍后,您可以使用以下查询检索它们:

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

1

我也是新手,对于NDB还不是很理解。但是我认为,当你创建一个父项为NapoleonBlah2时,你需要查询它的父项,否则它将不会出现。例如:

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

如果你没有使用正确的NDB格式,那么你将得不到任何东西,但是使用父级将会起作用:

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接