如何扩展SQLAlchemy的association_proxy的`getter`功能?
编辑:我想建立一个1 对 0:1
的关系,也就是说一个User
(用户)可以有零个或一个Comment
(评论)。我希望直接访问评论,而不是先访问Comment
对象。使用SQLAlchemy的association_proxy
可以很好地实现这个需求,但有一个问题:在没有关联Comment
的情况下访问User.comment
会出错。不过我希望在这种情况下返回None
,而不是AttributeError
错误。
看看下面的例子:
import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy import Column, Integer, Text, ForeignKey, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Text)
def __init__(self, name):
self.name = name
# proxy the 'comment' attribute from the 'comment_object' relationship
comment = association_proxy('comment_object', 'comment')
class Comment(Base):
__tablename__ = 'comments'
id = Column(Integer, primary_key=True)
comment = Column('comment', Text, nullable=False, default="")
user_id = Column(ForeignKey('users.id'), nullable=False, unique=True)
# user_id has to be unique to ensure that a User can not have more than one comments
def __init__(self, comment):
self.comment = comment
user_object = orm.relationship(
"User",
uselist=False, # added after edditing the question
backref=orm.backref('comment_object', uselist=False)
)
if __name__ == "__main__":
engine = sa.create_engine('sqlite:///:memory:', echo=True)
Session = orm.sessionmaker(bind=engine)
Base.metadata.create_all(engine)
session = Session()
现在,下面的代码会抛出一个AttributeError
错误:
u = User(name="Max Mueller")
print u.comment
有什么好的方法可以捕获这个错误,并提供一个默认值(比如空字符串)呢?
3 个回答
0
我没有看到任何能解决这个问题的答案,而且也能和“sort_by”一起使用的。
也许使用'column_property'会更好,具体可以参考这个链接:通过关联代理排序:无效的sql。
2
试试这个
import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy import Column, Integer, Text, ForeignKey, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Text)
def __init__(self, name):
self.name = name
# proxy the 'comment' attribute from the 'comment_object' relationship
comment = association_proxy('comment_object', 'comment')
class Comment(Base):
__tablename__ = 'comments'
id = Column(Integer, primary_key=True)
comment = Column('comment', Text, nullable=False, default="")
user_id = Column(ForeignKey('users.id'), nullable=False)
def __init__(self, comment):
self.comment = comment
user_object = orm.relationship(
"User",
backref=orm.backref('comment_object'),
uselist=False
)
if __name__ == "__main__":
engine = sa.create_engine('sqlite:///:memory:', echo=True)
Session = orm.sessionmaker(bind=engine)
Base.metadata.create_all(engine)
session = Session()
u = User(name="Max Mueller")
# comment = Comment("")
# comment.user_object = u
# session.add(u)
# session.commit()
print "SS :", u
print u.comment
你在 backref
中使用了 uselist
,但它必须在 relationship
中。
2
其实你并不需要用到association_proxy
。你完全可以用一个普通的property
就搞定了。出现AttributeError
错误的原因可能是因为comment_object
本身是None
,也就是说没有相关的行,而None
是没有comment
这个属性的。
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Text)
def __init__(self, name):
self.name = name
# proxy the 'comment' attribute from the 'comment_object' relationship
@property
def comment(self):
if self.comment_object is None:
return ""
else:
return self.comment_object.comment
@comment.setter
def comment(self, value):
if self.comment_object is None:
self.comment_object = Comment()
self.comment_object.comment = value