ndb Model - 检索有序的属性名称集

时间:2013-12-04 16:47:40

标签: python google-app-engine csv app-engine-ndb

我经常被要求将存储在NDB模型中的数据导出到csv。为此,我通常最终写出这样的模型:

from google.appengine.ext import ndb

class Foo(ndb.Model):
    monty = ndb.StringProperty()
    python = ndb.StringProperty()

    @property
    @classmethod
    def fieldnames(cls):
        return ['monty', 'python']

并在导出模块中的内容

# pseudocode ...

query = Foo.gql('where monty = :1', 'bunny')
data = [littlefoo._to_dict() for littlefoo in query]
fieldnames = Foo.fieldnames
with open('outfile.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames, dialect=dialect)
writer.writerows(data)

请注意,需要fieldnames方法来确定输出csv中字段的顺序。这种方法的问题在于,对于具有大量属性的任何模型,添加fieldnames方法都是丑陋的重复工作。理想情况下,我想在声明属性时简单地对属性进行排序,并以fieldnames的相同顺序检索它们。有没有办法按顺序检索这些属性? Foo._properties按字母顺序排列。

3 个答案:

答案 0 :(得分:4)

据我所知,如果不自己解析源代码,这是不可能的。幸运的是,有了python的“电池包含”心态,这并不难。您可以使用inspect获取源代码,然后您可以使用ast来解析源代码并订购内容:

import ast
import inspect

class NodeTagger(ast.NodeVisitor):
    def __init__(self):
        self.class_attribute_names = {}

    def visit_Assign(self, node):
        for target in node.targets:
            self.class_attribute_names[target.id] = target.lineno

    # Don't visit Assign nodes inside Function Definitions.
    def visit_FunctionDef(self, unused_node):
        return None

def order_properties(model):
    properties = model._properties
    source = inspect.getsource(model)
    tree = ast.parse(source)
    visitor = NodeTagger()
    visitor.visit(tree)
    attributes = visitor.class_attribute_names
    model._ordered_property_list = sorted(properties, key=lambda x:attributes[x])
    return model


@order_properties
class Foo(object):
    c = 1
    b = 2
    a = 3

    # Add a _properties member to simulate an `ndb.Model`.
    _properties = {'a': object, 'b': object, 'c': object}

print Foo._ordered_property_list

请注意,这里的方法几乎是一般的。我使用了ndb.Model具有_properties属性的知识,但该信息可能来自dirinspect.getmembers,因此可以修改order_properties以便它完全有效。

答案 1 :(得分:0)

我只是在做这件事,它可能充满了错误,但希望它能让你走上正确的道路:

from google.appengine.ext.ndb import Property

def get_field_names(ndbmodel):
    result = []
    all_fields = dir(ndbmodel)
    for field in all_fields:
        if isinstance(getattr(ndbmodel, field), Property):
            result.append(field)
    return result.sort()

答案 2 :(得分:0)

如果使用google.appengine.ext.db

db.Property实例具有一个名为creation_counter的属性,该属性在每次创建新实例时都会增加。因此,要获取按声明顺序排序的属性列表,可以执行以下操作:

sorted(Foo.properties().items(), key=lambda np: np[1].creation_counter)

(其中Foodb.Model的实例)

如果使用google.appengine.ext.ndb

相同,除了ndb.Property属性称为_creation_counter,因此等效代码为:

sorted(Foo._properties.items(), key=lambda np: np[1]._creation_counter)

(其中Foondb.Model的实例)