如何扩展 SQLAlchemy 的关联代理的 `getter` 功能?

发布于 2024-12-29 23:02:39 字数 1833 浏览 2 评论 0原文

编辑:我想在用户评论之间建立一个1到0:1关系(用户可以有零或一个评论)。我宁愿直接访问评论本身,而不是访问对象 Comment。使用 SQLAlchemys 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

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

Edit: I would like to model a 1 to 0:1 relationship between User and Comment (a User can have zero or one Comment). Instead of accessing the object Comment I would rather directly access the comment itself. Using SQLAlchemys association_proxy works perfect for that scenario except for one thing: accessing User.comment before having a Comment associated. But in this case I would rather expect None instead of AttributeError as result.

Look at the following example:

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()

Now, the following code throws an AttributeError:

u = User(name="Max Mueller")
print u.comment

What would be the best way to catch that exception and provide a default value instead (like an empty string)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陌上芳菲 2025-01-05 23:02:39

为此,您实际上并不需要association_proxy。您确实可以通过常规属性过得很好。 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

You don't really need association_proxy for this. You could really get by just fine with a regular property. The AttributeError is (probably) caused because the comment_object is itself None, since there is no dependent row, and None has no comment attribute.

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
山有枢 2025-01-05 23:02:39

试试这个

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 中。

Try this

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

You gave uselist in backref which must be in relationship.

季末如歌 2025-01-05 23:02:39

我没有看到任何可以解决问题并且也可以与“sort_by”一起使用的答案。

也许使用“column_property”更好,请参阅按关联代理排序:无效的sql< /a>.

I do not see any answer that would solve the issue and also would work with "sort_by" for example.

Maybe it is just better to use 'column_property", see Order by association proxy: invalid sql.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文