所以说我有一些类 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")
...
...
好的,所以这让我在课堂上有所收获,尽管我觉得我在用元类做一些愚蠢的事情,并且我遇到了一些奇怪的间歇性错误,其中据称“sqlalchemy”模块未被识别build_class_lens
并且评估为 Nonetype。
我不太确定我应该如何在实例级别进行。我查看了事件界面。我看到了 ORM 事件init
,但它似乎__init__
在我的模型上定义的函数之前运行,这意味着当时尚未填充实例属性,所以我无法在它们上构建我的“镜头”。我还想知道 Attribute 事件set
是否有帮助。那是我的下一次尝试,尽管我仍然想知道这是否是最合适的方式。
总而言之,我真的想知道我是否错过了一些非常优雅的方法来解决这个问题。