如何扩展SQLAlchemy的association_proxy的`getter`功能?

时间:2012-01-30 11:53:59

标签: python proxy sqlalchemy

修改:我想在1 to 0:1User之间建立Comment关系模型(用户可以有一个或一个评论)。我宁愿直接访问评论本身,而不是访问对象Comment。使用SQLAlchemys association_proxy非常适合该场景之外的一件事:在关联User.comment之前访问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

捕获该异常并提供默认值(如空字符串)的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

你真的不需要 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

答案 1 :(得分: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

您在uselist中提供的backref必须位于relationship