2011-11-09 5 views
0

Я отлично изучаю Python, но я только немного застрял в попытке включить рекурсивную функцию в SQLAlchemy.SQLAlchemy Recursion

По существу, есть функция, которая создает экземпляр класса, который должен быть помещен в базу данных. Внутри этой функции я получаю пользовательский ввод о том, имеет ли экземпляр родительский класс (определенный с использованием таблицы ссылочной смежности). Если это так, функция затем вызывается снова, рекурсивно. Эта функция работает, если родительский класс не нужен, но всякий раз, когда рекурсивный элемент активируется, он сбой.

Мой код следующим образом:

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

Я сохранил этот пример просто, чтобы сохранить его для чтения, но если я не хватает какой-то важной информацией, пожалуйста, дайте мне знать.

Я предположил, что моя проблема заключалась в том, что экземпляры класса теряли область по мере того, как я возвращался, но добавление глобального в переменную списка, похоже, не исправить. Я также думал, что тот факт, что сеанс действует как своего рода буфер, будет обрабатывать любые проблемы с областью.

Это как-то связано с eager loading? Я видел это в документации, но на самом деле не понимаю.

Ошибка я получаю:

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) 
+0

Прикрепление сообщения и отслеживание исключения, которое вы получите, безусловно, будет полезно. – Xion

+0

Сделаю, когда вернусь домой. У меня нет моего проекта здесь на работе. – abroekhof

+0

Неясно, какова область вашей сессии. Это может быть важно для понимания проблемы. Я думаю, что было бы лучше сократить ваш фактический код до минимума, убедиться, что он работает, а затем опубликовать его. – wberry

ответ

3

Я думаю, что у вас есть несколько ошибок/опечаток, которые делают ваш код не работает. Я предполагаю, что вы создали небольшой образец кода, чтобы показать проблему, и я надеюсь, что как только вы исправить их в исходном коде, проблема будет решена, а также:

  • вместо newIng.parentIng = parentIngObj вы должны иметь newIng.parent = parentIngObj. Я считаю, что это должно решить проблему.
    Итак, вы должны назначить родительский экземпляр объекту отношения, а не его ключу. Использование предложения JF Sebastian «s может работать также, если объекты уже были сохранены в базе данных, но новые экземпляры не имеют id назначен еще
  • addIngredient(...) имеет две проблемы:
    • опечатка: параметр ingredient должен быть переименован в ingName или наоборот
    • большая проблема: addIngredient(...) не возвращает никакого значения, поэтому на самом деле вы назначаете None стороне отношения parent.
      Опять же, учитывая, что это всего лишь пример кода, у вас могут не возникнуть проблемы в вашем реальном коде.
0
newIng.parentIng = parentIngObj.id 
+0

Является ли эта структура, потому что таблица является самореференциальной? Я назначил отношения ранее, используя структуру в моем коде, и, похоже, это сработало. Спасибо за ответ - я выстрелю, когда вернусь домой. – abroekhof