SQLAlchemy递归
我正在学习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
这一方。
再次强调,这只是一个示例代码,你在实际代码中可能不会遇到这些问题。
- 拼写错误:参数