#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. Является ли эта структура причиной того, что таблица ссылается на себя? Я назначил отношения ранее, используя структуру в моем коде, и, похоже, это сработало. Спасибо за ответ — я попробую, когда вернусь домой.