【问题标题】:Bidirectional relationship with association_proxy与 Association_proxy 的双向关系
【发布时间】:2014-07-28 22:27:19
【问题描述】:

我有两个模型,WordSentence,它们具有双向多对多关系。为了存储更多信息,我有一个关联对象,WordInSentence

class WordInSentence(Base):
    __tablename__ = "word_in_sentence"
    word_id = Column(Integer, ForeignKey('word.id'),
        primary_key=True)
    sentence_id = Column(Integer, ForeignKey('sentence.id'),
        primary_key=True)
    space_after = Column(String)
    tag = Column(String)
    position = Column(Integer)

    word = relationship("Word",
        backref=backref("word_sentences", lazy="dynamic"))
    sentence = relationship("Sentence",
        backref=backref("sentence_words", lazy="dynamic"))

class Sentence(Base):
    text = Column(Text, index = True)

    words = association_proxy("sentence_words", "word",
        creator=lambda word: WordInSentence(word=word))

class Word(Base):

    word = Column(String, index = True)
    sentences = association_proxy("word_sentences", "sentence",
        creator=lambda sent: WordInSentence(sentence=sent))

    def __repr__(self):
        return "<Word: " + str(self.word) + ">"

我希望能够做这样的事情:

w = Word()
s = Sentence()
w.sentences = [s]

但是,我收到如下错误:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/plasma/project/venv/lib/python2.7/site-packages/sqlalchemy/ext/associationproxy.py", line 274, in __set__
    proxy.clear()
  File "/home/plasma/project/venv/lib/python2.7/site-packages/sqlalchemy/ext/associationproxy.py", line 629, in clear
    del self.col[0:len(self.col)]
TypeError: object of type 'AppenderBaseQuery' has no len()

我还注意到文档中的this example,但我不确定如何使其成为双向和列表。

【问题讨论】:

    标签: python sqlalchemy relationship


    【解决方案1】:

    您收到错误TypeError: object of type 'AppenderBaseQuery' has no len() 的原因是您的关系设置为lazy="dynamic"。如果您实际检查该对象,它只是一个 SQL 查询。这就是为什么你不能迭代它 - 它必须首先执行。

    您可以通过使用适用于所有查询的标准函数来做到这一点 - 在对象上调用 filter(&lt;conditions&gt;),或者如果您想要一切,则调用 all()

    如果您不希望每次访问时都执行动态查询的额外步骤,另一种选择(如果关系中的子项数量不大)是将lazy 设置更改为'select'。然后,这将在查询父对象的同时运行关联查询,这对于庞大的子数据库当然是不切实际的,但对于较小的子数据库来说并非不合理。然后就可以按照你的预期进行迭代了。

    【讨论】:

      【解决方案2】:

      希望这段代码可以帮助到你。 我只是更改创建顺序并添加引擎和会话。 这是工作代码。

      from sqlalchemy.engine import create_engine
      from sqlalchemy.ext.associationproxy import association_proxy
      from sqlalchemy.ext.declarative.api import declarative_base
      from sqlalchemy.orm import relationship, backref
      from sqlalchemy.orm.session import Session
      from sqlalchemy.sql.schema import Column, ForeignKey
      from sqlalchemy.sql.sqltypes import Integer, String, Float, Date
      
      Base = declarative_base()
      
      class Sentence(Base):
          __tablename__ = 'sentence'
      
          id = Column(Integer, primary_key=True)
          text = Column(String, index = True)
      
          sentence_words = relationship('WordInSentence')
          words = association_proxy("sentence_words", "word")
      
      class Word(Base):
          __tablename__ = 'word'
      
          id = Column(Integer, primary_key=True)
          word = Column(String, index = True)
      
          word_sentences = relationship('WordInSentence')
          sentences = association_proxy("word_sentences", "sentence")
      
          def __repr__(self):
              return "<Word: " + str(self.word) + ">"
      
      
      class WordInSentence(Base):
          __tablename__ = "word_in_sentence"
      
          word_id = Column(Integer, ForeignKey(Word.id),
              primary_key=True)
          sentence_id = Column(Integer, ForeignKey(Sentence.id),
              primary_key=True)
          space_after = Column(String)
          tag = Column(String)
          position = Column(Integer)
      
          word = relationship(Word)
              #backref=backref("word_sentences", lazy="dynamic"))
          sentence = relationship(Sentence)
              #backref=backref("sentence_words", lazy="dynamic"))
      
      
      engine = create_engine('sqlite://')
      Base.metadata.create_all(engine)
      
      session = Session(engine)
      

      测试:

      >>> 
      >>> w = Word(word='something new')
      >>> w.sentences = [Sentence(text='there is somethine new')]
      >>> session.add(w)
      >>> session.commit()
      >>> session.query(WordInSentence).one().word_id
      1
      >>> session.query(Word).one().word
      'something new'
      >>> session.query(Sentence).one().text
      'there is somethine new'
      >>> 
      

      【讨论】:

      • 就是这样,谢谢。根据记录,创建顺序似乎并不重要。
      • @Plasma。很高兴,知道可以帮到你。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-06
      • 2013-04-05
      • 1970-01-01
      • 2011-02-09
      • 2016-12-05
      • 2014-07-23
      • 2012-08-26
      相关资源
      最近更新 更多