【发布时间】:2012-04-21 08:02:57
【问题描述】:
假设我有一些类 X、Y 和 Z 使用 SQLAlchemy 声明性语法来定义一些简单的列和关系
要求:
在类级别,
(X|Y|Z).primary_keys返回一个
的集合 相应类的“主键”(InstrumentedAttribute对象)我还希望(X|Y|Z).relations引用该类' 同样的关系在实例级别,我希望引用相同的属性 这些属性的实例化值,无论它们是否已经 使用我自己的构造函数、各个属性填充
设置器,或者 SQLAlchemy 在检索行时所做的任何事情 数据库。
到目前为止,我有以下内容。
import collections
import sqlalchemy
import sqlalchemy.ext.declarative
from sqlalchemy import MetaData, Column, Table, ForeignKey, Integer, String, Date, Text
from sqlalchemy.orm import relationship, backref
class IndexedMeta(sqlalchemy.ext.declarative.DeclarativeMeta):
"""Metaclass to initialize some class-level collections on models"""
def __new__(cls, name, bases, defaultdict):
cls.pk_columns = set()
cls.relations = collections.namedtuple('RelationshipItem', 'one many')( set(), set())
return super().__new__(cls, name, bases, defaultdict)
Base = sqlalchemy.ext.declarative.declarative_base(metaclass=IndexedMeta)
def build_class_lens(cls, key, inst):
"""Populates the 'indexes' of primary key and relationship attributes with the attributes' names. Additionally, separates "x to many" relationships from "x to one" relationships and associates "x to one" relathionships with the local-side foreign key column"""
if isinstance(inst.property, sqlalchemy.orm.properties.ColumnProperty):
if inst.property.columns[0].primary_key:
cls.pk_columns.add(inst.key)
elif isinstance(inst.property, sqlalchemy.orm.properties.RelationshipProperty):
if inst.property.direction.name == ('MANYTOONE' or 'ONETOONE'):
local_column = cls.__mapper__.get_property_by_column(inst.property.local_side[0]).key
cls.relations.one.add( (local_column, inst.key) )
else:
cls.relations.many.add(inst.key)
sqlalchemy.event.listen(Base, 'attribute_instrument', build_class_lens)
class Meeting(Base):
__tablename__ = 'meetings'
def __init__(self, memo):
self.memo = memo
id = Column(Integer, primary_key=True)
date = Column(Date)
memo = Column('note', String(60), nullable=True)
category_name = Column('category', String(60), ForeignKey('categories.name'))
category = relationship("Category", backref=backref('meetings'))
topics = relationship("Topic",
secondary=meetings_topics,
backref="meetings")
...
...
好的,这让我在课堂上顺利通过,虽然我觉得我在用元类做一些愚蠢的事情,而且我遇到了一些奇怪的间歇性错误,其中据称在 build_class_lens 中无法识别“sqlalchemy”模块,并且评估为 Nonetype。
我不太确定我应该如何在实例级别进行。
我查看了事件界面。我看到了 ORM 事件 init,但它似乎在我的模型上定义的 __init__ 函数之前运行,这意味着当时尚未填充实例属性,所以我无法构建我的“镜头”在他们。
我还想知道属性事件set 是否有帮助。那是我的下一次尝试,虽然我仍然想知道这是否是最合适的方式。
总而言之,我真的想知道我是否错过了一些非常优雅的方法来解决这个问题。
【问题讨论】:
标签: python sqlalchemy