Рекурсия SQLAlchemy

#python #recursion #sqlalchemy

#python #рекурсия #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()
  

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

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

Имеет ли это какое-то отношение к быстрой загрузке? Я видел это в документации, но на самом деле не понимаю.

Ошибка, которую я получаю, заключается в:

 Traceback (most recent call last):
  File "C:workspacerecipeslangProc.py", line 102, in <module>
    session.commit()
  File "c:Python27libsite-packagessqlalchemyormsession.py", line 645, in commit
    self.transaction.commit()
  File "c:Python27libsite-packagessqlalchemyormsession.py", line 313, in commit
    self._prepare_impl()
  File "c:Python27libsite-packagessqlalchemyormsession.py", line 297, in _prepare_impl
    self.session.flush()
  File "c:Python27libsite-packagessqlalchemyormsession.py", line 1547, in flush
    self._flush(objects)
  File "c:Python27libsite-packagessqlalchemyormsession.py", line 1616, in _flush
    flush_context.execute()
  File "c:Python27libsite-packagessqlalchemyormunitofwork.py", line 328, in execute
    rec.execute(self)
  File "c:Python27libsite-packagessqlalchemyormunitofwork.py", line 472, in execute
    uow
  File "c:Python27libsite-packagessqlalchemyormmapper.py", line 2153, in _save_obj
    execute(statement, params)
  File "c:Python27libsite-packagessqlalchemyenginebase.py", line 1399, in execute
    params)
  File "c:Python27libsite-packagessqlalchemyenginebase.py", line 1532, in _execute_clauseelement
    compiled_sql, distilled_params
  File "c:Python27libsite-packagessqlalchemyenginebase.py", line 1640, in _execute_context
    context)
  File "c:Python27libsite-packagessqlalchemyenginebase.py", line 1633, in _execute_context
    context)
  File "c:Python27libsite-packagessqlalchemyenginedefault.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)
  

Комментарии:

1. Прикрепление сообщения и трассировка полученного исключения, безусловно, были бы полезны.

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

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

4. Хм, этот код значительно сокращен по сравнению с тем, что у меня есть в настоящее время — не уверен, как бы я сократил его дальше. Я добавил создание экземпляра сеанса и сообщения об ошибках. Надеюсь, это поможет?

Ответ №1:

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

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

Ответ №2:

 newIng.parentIng = parentIngObj.id
  

Комментарии:

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