如何修改ndb.Query对象?

时间:2012-09-25 20:14:02

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

我们假设我们使用以下ndb模型:

class MyModel(ndb.Model):
    x = ndb.StringProperty()
    y = ndb.StringProperty()
    z = ndb.StringProperty(repeated=True)

我们有一个方法可以为上面的模型创建一个查询,执行它并获取结果。但是,我们希望此查询可以修改我的其他功能。具体来说,我们有以下内容:

def method_a():
    qry = MyModel.query() 
    values = {'query':qry}
    method_b(**values)
    entities = qry.fetch()

def method_b(**kwargs):
    k = ['a', 'b', 'c']
    qry = kwargs['query']
    qry.filter(MyModel.z.IN(k))

问题是Query对象是不可变的,因此method_b不能修改它。此外,基于代码的特定体系结构,我们不能让method_b将新的Query返回给method_a。

关于如何以另一种方式实现上述功能的任何想法?

更新:请检查我的代码架构,如下所示:

首先,在配置文件中,我们指定模块列表以及是否启用它们。这些模块会影响我们要执行的查询的过滤器。

testparams = {
    'Test1': True,
    'Test2': True,
    'Test3': False,
    'Test4': True
}

然后,我们在代码中的某个地方有一个方法,在执行适当的模块之后进行查询。因此,看起来像这样:

def my_func():
    qry = MyEntity.query()

    # modules
    query_wrapper = [qry]
    values = {'param':'x', 'query_wrapper':query_wrapper} #other values also
    execute_modules(**values)
    # get query and add some more things, like ordering
    entities = query_wrapper[0].fetch()

execute_modules功能如下:

def execute_modules(**kwargs):
    for k in config.testparams:
        if config.testparams[k]:
            if kwargs['param'] == 'x':
                (globals()[k]).x(**kwargs)
            elif kwargs['param'] == 'y':
                (globals()[k]).y(**kwargs)

最后,指示性模块类似于以下内容:

class Test1():
    @classmethod
    def x(cls, *args, **kwargs):
        qry = kwargs['query_wrapper'][0]
        # do some stuff like adding filters
        kwargs['query_wrapper'][0] = qry

是否有任何建议将此架构修改为更好的方法?

3 个答案:

答案 0 :(得分:1)

如果没有method_b返回或更改引用的参数,我就不知道这样做的方法。您应该使用pass a variable by reference的技术,就像传递带参数的类一样。

答案 1 :(得分:1)

您可以传入refrence对象中的args,例如dict / list:

def modify_query(kwargs):
  kwargs['qry'] = kwargs['qry'].filter(MyModel.z.IN(k))

qry = MyModel.query()
kwargs = {'qry': qry}
modify_query(kwargs)
result = kwargs['qry'].fetch()

应该注意的是,这是完成你想要完成的事情的一种非常肮脏的方式。类似地,如果您传入一个包含一个对象的列表,那么您可以修改所述列表的内容(通过赋值)来修改该对象:

def modify_query(list_object):
  list_object[0] = list_object[0].filter(...)

答案 2 :(得分:0)

你可以做一些黑客来替换其他人的对象。例如:

def f(args):
  qry = args[0]
  qry_new = qry.filter(Model.a == 2)
  args[0] = qry_new

qry = Model.query()
args = [qry]
f(args)
qry = args[0]