SQLAlchemy:了解模型对象的字段名称和值?

时间:2013-12-29 10:40:46

标签: python json sqlalchemy pyramid solid-principles

我正在尝试保持SOLID面向对象的编程原则,保持DRY等,但我对Python / SQLAlchemy / Pyramid的新见感正在使它变得非常困难。

我正在尝试将我现在所知道的SQLAlchemy模型用于创建一个简单的Pyramid Framework对象并使用我所知道的C#中的“反射”,它可能在Python中被称为不同的东西(Introspection?不确定,因为这只是我第二周的python,但我有很多其他语言的经验(C / C ++ / C#,Java等)所以麻烦似乎是把我的知识映射到python的词汇表,抱歉),到找出数据库表的字段名,最重要的是当前字段值,当我事先不知道列名或任何形状的对象时。

多数民众赞成;我不知道'derp'实例有一个名为id或name的字段,只是它有每个列中的列和值。这就是我所关心的。

目标是能够获取任何SQLAlchemy定义的数据模型,并将其转换为column_name的字典 - >在JSON中找到的那种简单数据类型的column_value字段,因为我想最终将我在SQLAlchemy中创建的任何对象序列化为json对象,但是只要字典包含正确的类型,我将从那里解决它的简单问题数据的。手动对每个对象执行此操作违反了太多良好的清洁代码规则,并且会随着时间的推移创建太多的工作;我可以在这上花一个星期的时间,但仍然可以通过正确的方式来节省时间和精力。

因此,如果我在SQLAlchemy中定义了一个类:

class SimpleFooModel(Base):
    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    name = Column(VARCHAR(length=12), nullable=False, index=True)

..我有一个等于(在python中)的实例:

derp = SimpleFooModel(id=7, name="Foobar")

我希望能够只拥有上面描述的'derp'实例变量,并且不知道模型是如何形成的,并且能够将其展平为python key->值字典以实现简单对象,其中该字典中的每个值都可以使用python syslib中的import json序列化为JSON。

问题是,我已经看了2天,我找不到一个答案,可以在我的单元测试中得到我想要的结果任何地方;谷歌一直把我带到这里的老帖子,关于那些使用不再适用的接口的图书馆的旧版本,或者已经接受了根本不起作用的答案;并且由于它们中没有一个是最近让我感到惊讶的(但是为什么Stack Overflow在他们出错时保留它们并允许谷歌误导人们确实让我感到惊讶)

我知道我可以手动为每个对象连接每个对象到json等,但这不仅不优雅,效率低,因为它只是为我创造了更多的工作,因为我创造了更多的对象,并可能导致大路上的大错。我想知道如何以正确的方式做到这一点,有内省/反思,但似乎没有人知道,并且声称在堆栈溢出的所有给出示例的人实际上根本不起作用(至少对于当前事物的版本)

这对我来说似乎是一个非常常见的用例;并获取列字段列表,然后使用getattr迭代它 - 就像许多答案所说的那样 - 也不能按预期工作;它只是创建看起来像永远不会返回列的实际值的名称空间,并且实际上不存在于任何代码中,因为sqlalchmy创建的字段都不是单例/静态。

所以:

    from sqlalchemy.inspection import inspect

    obj = inspect(derp, raiseerr=True)

    for key in obj.attrs.keys():
        fields[key] = getattr(derp, key)
        print fields[key]

请给我:

    [Class Name].[Column Name]

..或者在这种情况下只是给了我:

    SimpleFooModel.id
    SimpleFooModel.name

不分别为id和name的值7和“Foobar”,这是我在测试中实际预期的。

事实上,我似乎无法找到WHERE值存储在对象模型中;或者我可以强行解决这个问题,让他们从那里作为一个丑陋的,邪恶的黑客,我会羞于看。我通过“官方公共API”获得的很多对象似乎都不知道存储真实数据的位置,但很高兴地告诉我列名称和类型,限制等所使用的路径的名称......而不是我想要的实际数据。

然而,由于我的要求是我不提前知道字段名称,使用derp.id或derp.name调用来收集值不是一个选项,因为这会违反SOLID并迫使我重复工作每一堂课。所以它不是一个选择。

也许它是我在2天内没有睡觉的事实,但我真的很难在这些书中看不出这是一个严重的设计缺陷;我只想将表示表中单行的SQLAlchemy定义的Model对象序列化为python字典而不必事先知道字段的名称,而且许多其他语言使这变得容易或甚至是微不足道的,这似乎是远远的太难了。

有人可以解释一个有效的解决方案,或者为什么我想将SOLID应用于我的代码?

编辑:更新拼写。

1 个答案:

答案 0 :(得分:4)

使用以下课程扩展您的模型:

class BaseModel(object):

    @classmethod
    def _get_keys(cls):
        return sa.orm.class_mapper(cls).c.keys()

    def get_dict(self):
        d = {}
        for k in self._get_keys():
            d[k] = getattr(self, k)
        return d

这将完全符合您的要求,以{'column_name':'value'}对的形式返回一个字典。