tij*_*ijs 5 google-app-engine gql google-cloud-datastore
我有一个包含IP地址范围的模型,类似于:
class Country(db.Model):
begin_ipnum = db.IntegerProperty()
end_ipnum = db.IntegerProperty()
Run Code Online (Sandbox Code Playgroud)
在SQL数据库上,我将能够找到包含特定范围内的IP的行,如下所示:
SELECT * FROM Country WHERE ipnum BETWEEN begin_ipnum AND end_ipnum
Run Code Online (Sandbox Code Playgroud)
或这个:
SELECT * FROM Country WHERE begin_ipnum < ipnum AND end_ipnum > ipnum
Run Code Online (Sandbox Code Playgroud)
遗憾的是,GQL只允许在一个属性上使用不等式过滤器,并且不支持BETWEEN语法.我如何解决这个问题,并在App Engine上构建一个与这些相当的查询?
此外,ListProperty创建记录时可以"生存"还是必须计算?
首先尝试解决方案更新问题:
所以根据David的答案以及以下文章:
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)
Run Code Online (Sandbox Code Playgroud)
我的想法是,在我添加自定义属性后,我可以按原样导入我的数据集,然后根据ListProperty运行查询,如下所示:
q = Country.gql('WHERE ip_range = :1', my_num_ipaddress)
Run Code Online (Sandbox Code Playgroud)
当我尝试插入新的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
Run Code Online (Sandbox Code Playgroud)
我尝试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)
Run Code Online (Sandbox Code Playgroud)
更好的解决方案(最终 - 由于错误,目前以下仅适用于开发服务器(请参阅问题 798)。理论上,您可以解决您提到的限制并通过利用 howdb.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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1909 次 |
| 最近记录: |