Python 从非orm类继承SQLAlchemy
我正在尝试开发非ORM类的ORM版本,以便能够将对象存储在数据库中(如果可能的话,还可以检索回来) 我现在想要实现的是一个类似的对象,它的行为类似于Python世界中的Python 从非orm类继承SQLAlchemy,python,inheritance,orm,sqlalchemy,ruamel.yaml,Python,Inheritance,Orm,Sqlalchemy,Ruamel.yaml,我正在尝试开发非ORM类的ORM版本,以便能够将对象存储在数据库中(如果可能的话,还可以检索回来) 我现在想要实现的是一个类似的对象,它的行为类似于Python世界中的User,但也可以用作ORM对象,因此可以将其存储在数据库中。我巧妙地尝试的是: Base = declarative_base() class SQLUser(Base, User): id = Column(Integer, primary_key=True) name = Column(String)
User
,但也可以用作ORM对象,因此可以将其存储在数据库中。我巧妙地尝试的是:
Base = declarative_base()
class SQLUser(Base, User):
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
def __init__(self, name, age):
self.name = name
self.age = age
在Python 2上运行具有此类层次结构的示例会产生以下错误:
类型错误:调用元类基时出错
元类冲突:派生类的元类必须是其所有基元类的(非严格)子类
我相信这与YAMLObject
元类有关。。。但是我需要它,因为我希望能够将这些对象保存为YAML。对于我读到的关于这个错误的内容,我可能应该使用第三个元类,该元类继承自YAMLObject
元类和Base
,然后使用它创建我想要的类
class MetaMixinUser(type(User), type(Base)):
pass
class SQLUser(six.with_metaclass(MetaMixinUser)):
#[...]
不幸的是,这会产生另一个错误:
AttributeError:类型对象“SQLUser”没有属性“\u decl\u class\u registry”
您能告诉我我的推理哪里有缺陷吗?如果您赶时间:从
ruamel.yaml
0.15.19开始,您可以只使用一条语句,而无需对yamobject
进行子类化:
yaml = ruamel.yaml.YAML()
yaml.register_class(User)
import sys
import ruamel.yaml
from ruamel.std.pathlib import Path
yaml = ruamel.yaml.YAML(typ='unsafe')
class User(ruamel.yaml.YAMLObject):
yaml_tag = u'user'
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def to_yaml(cls, representer, node):
return representer.represent_scalar(cls.yaml_tag,
u'{.name}-{.age}'.format(node, node))
@classmethod
def from_yaml(cls, constructor, node):
# type: (Any, Any) -> Any
return User(*node.value.split('-'))
data = {'users': [User('Anthon', 18)]}
yaml.dump(data, sys.stdout)
print()
tmp_file = Path('tmp.yaml')
yaml.dump(data, tmp_file)
rd = yaml.load(tmp_file)
print(rd['users'][0].name, rd['users'][0].age)
YAMLObject
是为了向后兼容PyYAML而存在的,尽管它可能很方便,但我并不推荐使用它,原因有三:
YAMLObject
,正如您所注意到的,这可能会干扰其他依赖关系加载程序
YAMLObject
所做的唯一真正的事情是为该yaml_标记注册一个构造函数
,为子类注册一个representer
如果运行Python2,所有示例都假定来自_ufuture _uu import print_函数的
根据子类化YAMLObject
,如果您有以下内容:
yaml = ruamel.yaml.YAML()
yaml.register_class(User)
import sys
import ruamel.yaml
from ruamel.std.pathlib import Path
yaml = ruamel.yaml.YAML(typ='unsafe')
class User(ruamel.yaml.YAMLObject):
yaml_tag = u'user'
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def to_yaml(cls, representer, node):
return representer.represent_scalar(cls.yaml_tag,
u'{.name}-{.age}'.format(node, node))
@classmethod
def from_yaml(cls, constructor, node):
# type: (Any, Any) -> Any
return User(*node.value.split('-'))
data = {'users': [User('Anthon', 18)]}
yaml.dump(data, sys.stdout)
print()
tmp_file = Path('tmp.yaml')
yaml.dump(data, tmp_file)
rd = yaml.load(tmp_file)
print(rd['users'][0].name, rd['users'][0].age)
这将使你:
users: [!<user> Anthon-18]
Anthon 18
上面使用的是SafeLoader
(和SafeDumper
),这是朝着正确方向迈出的一步。但是,如果您有很多类,那么添加上面的XXXX.add_YYY
行会很麻烦,因为这些条目几乎相同,但并不完全相同。而且它不会处理缺少到\u yaml
的和来自\u yaml
的的类
为了解决上述问题,我建议您在文件myyaml.py
中创建一个decoratoryaml\u对象和一个helper类:
import ruamel.yaml
yaml = ruamel.yaml.YAML(typ='safe')
class SafeYAMLObject(object):
def __init__(self, cls):
self._cls = cls
def to_yaml(self, representer, data):
return representer.represent_yaml_object(
self._cls.yaml_tag, data, self._cls,
flow_style=representer.default_flow_style)
def from_yaml(self, constructor, node):
return constructor.construct_yaml_object(node, self._cls)
def yaml_object(cls):
yaml.representer.add_representer(
cls, getattr(cls, 'to_yaml', SafeYAMLObject(cls).to_yaml))
yaml.constructor.add_constructor(
cls.yaml_tag, getattr(cls, 'from_yaml', SafeYAMLObject(cls).from_yaml))
return cls
有了这些,你可以:
import sys
from ruamel.std.pathlib import Path
from myyaml import yaml, yaml_object
@yaml_object
class User(object):
yaml_tag = u'user'
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def to_yaml(cls, representer, node):
return representer.represent_scalar(cls.yaml_tag,
u'{.name}-{.age}'.format(node, node))
@classmethod
def from_yaml(cls, constructor, node):
# type: (Any, Any) -> Any
return User(*node.value.split('-'))
data = {'users': [User('Anthon', 18)]}
yaml.dump(data, sys.stdout)
print()
tmp_file = Path('tmp.yaml')
yaml.dump(data, tmp_file)
rd = yaml.load(tmp_file)
print(rd['users'][0].name, rd['users'][0].age)
同样的结果。如果从_yaml
方法中删除到_yaml
和,则会得到相同的最终值,但yaml略有不同:
users:
- !<user> {age: 18, name: Anthon}
Anthon 18
⑨
免责声明:我是本回答中使用的ruamel.yaml
包的作者。
免责声明2:我并不是真正的18岁,但我确实遵循了布莱恩·亚当斯(Brian Adams)在专辑标题歌中表达的观点你不必继承自YAMLObject
就可以转储用户
。子类化是实现转储和加载的最具侵入性的方式。您的User
类可能无法工作,因为它没有yaml\u标记。您是否愿意删除对YAMLObject
的依赖关系?@Anthon抱歉,我省略了yaml\u标记,但它就在那里。我编辑了我的问题。User
类本身工作正常(我实现了to_yaml
方法,使类能够正确地转储到yaml文件中)。我对一切都是开放的,但通过这种方式,我可以以透明的方式将对象转储给最终用户。只需一个yaml.dump
就可以像预期的那样工作……我补充道。我不确定您在回答中实际使用了哪些解决方案,但注册应该对您有效,装饰可能仍然会干扰您,因为它具有包装功能。@Anthon我按照您的建议使用了装饰器,并且在我做的简短测试中,继承按预期工作。谢谢你的帮助和支持!
class SQLUser(Base, User):