我想:
session.query
的类似于对象的对象。这应该跨越关系,例如employee.company.name
,其中company是Employee模型中的关系字段。defer
或.load_only('field_name')
但是其他人可以访问我没有指定的模型属性,这将导致另一个查询运行。理想情况下,即使在模型中定义了该字段,访问查询中未指定的字段也会引发AttributeError
。这是否可以使用SqlAlchemy提供的机制?这甚至是个好主意吗?
我编写了以下功能,可以满足我的需求,但似乎其他人必须以更好,更标准的方式满足这些需求。
class Attributable(object):
pass
def spread_result(row, columns):
"""
:type row: sqlalchemy.util._collections.KeyedTuple
:type columns: tuple
Usage:
>>> result = session.query(Model.field, AnotherModel.other_field).first()
>>> obj = spread_result(result, ('field', 'another_model.other_field'))
>>> obj.field
'field_value'
>>> obj.another_model.other_field
'other_field_value'
>>> obj.another_mapped_field
AttributeError: 'Attributable' object has no attribute 'another_mapped_field'
"""
root = Attributable()
for column, value in zip(columns, row):
obj = root
parts = column.split('.')
for i, attr in enumerate(parts):
if i == len(parts) - 1:
setattr(obj, attr, value)
else:
setattr(obj, attr, Attributable())
obj = getattr(obj, attr)
return root
答案 0 :(得分:1)
最简单的方法是创建一个" public"映射到同一个表但仅包含您希望可加载/可访问的列和其他属性的模型。
include_properties或exclude_properties参数可以指定只应映射列的子集
如果您有一个Person模型,用户应该只看到id和名称," public" class会是这样的:
class PublicPerson(Base):
__table__ = Person.__table__
__mapper_args__ = {
'include_properties': ['id', 'name']
}
这是一个简单的可运行示例:
from datetime import datetime
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
engine = create_engine('sqlite://', echo=True)
session = Session(bind=engine)
Base = declarative_base(bind=engine)
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
birthday = Column(DateTime, nullable=False)
class PublicPerson(Base):
__table__ = Person.__table__
__mapper_args__ = {
'include_properties': ['id', 'name']
}
Base.metadata.create_all()
session.add(Person(name='Jan', birthday=datetime(2001, 1, 1)))
# query the full person, prints birthday
print(session.query(Person.birthday).scalar())
# query the "public" person, raises exception on birthday
print(session.query(PublicPerson.birthday).scalar())