google-app-engine - 在 App Engine 数据存储区的等效查询之间?

标签 google-app-engine google-cloud-datastore gql

我有一个包含 IP 地址范围的模型,类似于:

class Country(db.Model):
  begin_ipnum = db.IntegerProperty()
  end_ipnum = db.IntegerProperty()

在 SQL 数据库上,我可以像这样找到包含特定范围内 IP 的行:

SELECT * FROM Country WHERE ipnum BETWEEN begin_ipnum AND end_ipnum

或者这个:

SELECT * FROM Country WHERE begin_ipnum < ipnum AND end_ipnum > ipnum

遗憾的是,GQL 只允许对一个属性进行不等式过滤,并且不支持 BETWEEN 语法。我该如何解决这个问题并构建与 App Engine 上的查询等效的查询?

此外,ListProperty 可以是“实时的”还是必须在创建记录时计算?

问题已更新为第一个解决方案:

所以根据下面大卫的回答和诸如此类的文章:

http://appengine-cookbook.appspot.com/recipe/custom-model-properties-are-cute/

我正在尝试像这样向我的模型添加自定义字段:

class IpRangeProperty(db.Property):
  def __init__(self, begin=None, end=None, **kwargs):
    if not isinstance(begin, db.IntegerProperty) or not isinstance(end, db.IntegerProperty):
        raise TypeError('Begin and End must be Integers.')
    self.begin = begin
    self.end = end
    super(IpRangeProperty, self).__init__(self.begin, self.end, **kwargs)

  def get_value_for_datastore(self, model_instance):
    begin = self.begin.get_value_for_datastore(model_instance)
    end = self.end.get_value_for_datastore(model_instance)
    if begin is not None and end is not None:
      return range(begin, end)

class Country(db.Model):
  begin_ipnum = db.IntegerProperty()
  end_ipnum = db.IntegerProperty()
  ip_range = IpRangeProperty(begin=begin_ipnum, end=end_ipnum)

我的想法是,在我添加自定义属性后,我可以按原样导入我的数据集,然后基于 ListProperty 运行查询,如下所示:

q = Country.gql('WHERE ip_range = :1', my_num_ipaddress)

当我尝试插入新的 Country 对象时失败了,提示无法创建名称:

...
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/db/__init__.py", line 619, in _attr_name
return '_' + self.name
TypeError: cannot concatenate 'str' and 'IntegerProperty' objects

我尝试为新属性定义一个 attr_name 方法或只是设置 self.name 但这似乎没有帮助。是无可救药地停滞不前还是正朝着正确的方向前进?

最佳答案

简短回答:目前并不真正支持查询之间。但是,如果您先验地知道您的范围将相对较小,那么您可以伪造它:只需在实体上存储一个列表,每个 范围内的数字。然后,您可以使用简单的相等过滤器来获取范围包含特定值的实体。显然,如果您的范围很大,这将行不通。但它是这样工作的:

class M(db.Model):
    r = db.ListProperty(int)

# create an instance of M which has a range from `begin` to `end` (inclusive)
M(r=range(begin, end+1)).put()

# query to find instances of M which contain a value `v`
q = M.gql('WHERE r = :1', v)

更好的解决方案(最终 - 由于错误,目前以下仅适用于开发服务器(请参阅 issue 798 )。理论上,您可以解决您提到的限制并执行范围查询通过利用如何查询 db.ListProperty。这个想法是将范围的开始和结束存储在列表中(在您的情况下,表示 IP 地址的整数)。然后获取范围包含某些值的实体v(即,在列表中的两个值之间),您只需使用列表上的两个不等式过滤器执行查询 - 一个确保 v 至少与列表中的最小元素一样大,并且确保 v 至少与列表中最大的元素一样小。

这是一个如何实现此技术的简单示例:

class M(db.Model):
    r = db.ListProperty(int)

# create an instance of M which has a rnage from `begin` to `end` (inclusive)
M(r=[begin, end]).put()

# query to find instances of M which contain a value `v`
q = M.gql('WHERE r >= :1 AND r <= :1', v)

关于google-app-engine - 在 App Engine 数据存储区的等效查询之间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3338109/

相关文章:

google-app-engine - 去包冲突

python - 另一个 StructuredProperty 中的 StructuredProperty。如何?

python - 构建一个对 ReferenceProperty 有条件的 GQL 查询(针对 Google App Engine)

database - GQL 语法中的子选择(数据存储查看器)

java - 从 Java 中的谷歌计算引擎与数据存储和云存储通信

google-app-engine - GAE 数据存储查看器中的 utf8 错误(Go 运行时)

java - 在数据库操作上发布事件

google-app-engine - GQL随机记录

android - 如何使用 Google App Engine 作为 Android 应用程序的后端数据库

google-app-engine - 在 Google 应用引擎上更改模型的后果