SQLAlchemy递归

1 投票
2 回答
2188 浏览
提问于 2025-04-17 05:56

我正在学习Python,感觉很不错,但在把递归函数放进SQLAlchemy的时候遇到了一些问题。

简单来说,我有一个函数,它会创建一个类的实例,然后把它放进数据库。在这个函数里,我会询问用户这个实例是否有父类(这个父类是通过一个自引用的邻接表来定义的)。如果有父类,函数就会再次被调用,也就是递归调用。当不需要父类时,这个函数似乎能正常工作,但一旦需要递归,它就崩溃了。

我的代码大致是这样的:

engine = create_engine('sqlite:///recDB.db')
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()

class IngList(Base):
    __tablename__ = "ingList"

    id = Column(Integer, primary_key = True)
    ingredient = Column(String, nullable=False)
    parentIng = Column(Integer, ForeignKey('ingList.id'))
    children = relationship("IngList",backref=backref('parent', remote_side=[id]))

    def __init__(self, ingredient):
        self.ingredient = ingredient

def addIngredient(ingredient):
    global newIngList
    newIng = IngList(ingName) #create new class instance
    parentIng = raw_input("To add parent ingredient, type it.  Otherwise press enter")
    if parentIng != '':
        parentIngObj = addIngredient(parentIng) # Recursion!
        newIng.parentIng = parentIngObj
    newIngList.append(newIng)

if __name__ == '__main__':
    newIngList = []
    ingredient = raw_input("Enter new ingredient")
    addIngredient(ingredient)
    for ing in newIngList
        session.add(ing)
    session.commit()

我把这个示例保持得简单,以便于阅读,但如果我漏掉了什么重要的信息,请告诉我。

我原以为问题出在递归时类的实例失去了作用域,但把全局变量加到列表里似乎并没有解决这个问题。我还觉得会话(session)就像一个缓冲区,应该能处理任何作用域的问题。

这跟预加载有关吗?我在文档里看到过这个,但不太明白。

我遇到的错误是:

Traceback (most recent call last):
  File "C:\workspace\recipes\langProc.py", line 102, in <module>
    session.commit()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 645, in commit
    self.transaction.commit()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 313, in commit
    self._prepare_impl()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 297, in _prepare_impl
    self.session.flush()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1547, in flush
    self._flush(objects)
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1616, in _flush
    flush_context.execute()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\unitofwork.py", line 328, in execute
    rec.execute(self)
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\unitofwork.py", line 472, in execute
    uow
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 2153, in _save_obj
    execute(statement, params)
  File "c:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1399, in execute
    params)
  File "c:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1532, in _execute_clauseelement
    compiled_sql, distilled_params
  File "c:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1640, in _execute_context
    context)
  File "c:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1633, in _execute_context
    context)
  File "c:\Python27\lib\site-packages\sqlalchemy\engine\default.py", line 330, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.InterfaceError: (InterfaceError) Error binding parameter 0 
- probably unsupported type.
u'UPDATE "ingList" SET "parentIng"=? WHERE "ingList".id = ?' 
(<assignDB.IngList object at 0x00000000096969E8>, 4)

2 个回答

0
newIng.parentIng = parentIngObj.id

当然可以!请把你想要翻译的内容发给我,我会帮你把它变得更简单易懂。

3

我觉得你的代码里有几个小错误或者拼写错误,这让它无法正常工作。我猜你是为了展示问题而写了一个小代码示例,希望你在原始代码中修复这些问题后,问题也能解决:

  • 你应该把 newIng.parentIng = parentIngObj 改成 newIng.parent = parentIngObj。我相信这样就能解决问题。
    你需要把父级实例赋值给关系对象,而不是它的键。如果使用 J.F. Sebastian 的建议也可以,但前提是这些对象已经存储在数据库中,而新的实例还没有分配 id
  • addIngredient(...) 有两个问题:
    • 拼写错误:参数 ingredient 应该改名为 ingName,或者反过来。
    • 更大的问题是:addIngredient(...) 没有返回任何值,所以实际上你把 None 赋值给了关系的 parent 这一方。
      再次强调,这只是一个示例代码,你在实际代码中可能不会遇到这些问题。

撰写回答