Пирамида: DBSession.add(модель) возвращает ошибку типа

#python #sqlalchemy #pyramid

#python #sqlalchemy #пирамида

Вопрос:

Когда я запускаю initializedb.py скрипт, мои таблицы создаются нормально, но когда я пытаюсь вставить какие-либо данные, я получаю следующую ошибку:

 TypeError: unbound method after_attach() must be called with ZopeTransactionExtension instance as first argument (got Session instance instead)
  

Почему я получаю эту ошибку? Я попытался найти ошибку в Google, но единственный пример, связанный со мной, который я нашел, был связан с неправильным запросом.

Моя структура пакета и соответствующие разделы кода следующие:

В моем приложении Pyramid вместо определения всех моделей в models.py файле я создал отдельный пакет под названием models и поместил туда все мои классы моделей.

В принципе, у меня есть

 myapp/
    models/
        __init__.py
        meta.py
        school.py
    __init__.py
  

Мой основной __init__.py имеет:

 from myapp.models.meta import (
    DBSession,
    Base,
    )
  

Аналогично, __init__.py файл внутри models имеет:

 from .meta import DBSession
from .school import School
  

meta.py внутри models есть:

 from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
    )
from zope.sqlalchemy import ZopeTransactionExtension

Base = declarative_base()
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension))
  

Файл модели school.py имеет:

 from .meta import (
    Base,
    get_prefix,
    )

class School(Base):
    """ The SQLAlchemy declarative model class for a School object. """
    __tablename__ = 'schools'

    id = Column(Integer, primary_key=True)
    school_code = Column(String(10))
  

И, наконец, scripts/initializedb.py файл имеет:

 from myapp.models.meta import (
    Base,
    DBSession,
    )

from myapp.models import (
    School,
    )
def main(argv=sys.argv):
    if len(argv) < 2:
        usage(argv)
    config_uri = argv[1]
    options = parse_vars(argv[2:])
    setup_logging(config_uri)
    settings = get_appsettings(config_uri, options=options)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)
    with transaction.manager:
        demo_school = School(school_code="SC-123")
        DBSession.add(demo_school)
  

Редактировать:

Полная трассировка выглядит следующим образом:

 2014-06-22 20:18:31,577 INFO  [sqlalchemy.engine.base.Engine][MainThread] SHOW VARIABLES LIKE 'sql_mode'
2014-06-22 20:18:31,577 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,585 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Col ('Variable_name', 'Value')
2014-06-22 20:18:31,586 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Row ('sql_mode', '')
2014-06-22 20:18:31,586 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT DATABASE()
2014-06-22 20:18:31,586 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,587 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Col ('DATABASE()',)
2014-06-22 20:18:31,587 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Row ('myapp',)
2014-06-22 20:18:31,588 INFO  [sqlalchemy.engine.base.Engine][MainThread] show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'
2014-06-22 20:18:31,588 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,590 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Col ('Collation', 'Charset', 'Id', 'Default', 'Compiled', 'Sortlen')
2014-06-22 20:18:31,591 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Row ('utf8_bin', 'utf8', 83L, '', 'Yes', 1L)
2014-06-22 20:18:31,592 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1
2014-06-22 20:18:31,592 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,593 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1
2014-06-22 20:18:31,593 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,594 INFO  [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin AS anon_1
2014-06-22 20:18:31,595 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,596 INFO  [sqlalchemy.engine.base.Engine][MainThread] DESCRIBE `a3fhs32g_schools`
2014-06-22 20:18:31,597 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,598 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Col ('Field', 'Type', 'Null', 'Key', 'Default', 'Extra')
2014-06-22 20:18:31,598 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Row ('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
2014-06-22 20:18:31,598 INFO  [sqlalchemy.engine.base.Engine][MainThread] DESCRIBE `a3fhs32g_students`
2014-06-22 20:18:31,598 INFO  [sqlalchemy.engine.base.Engine][MainThread] ()
2014-06-22 20:18:31,599 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Col ('Field', 'Type', 'Null', 'Key', 'Default', 'Extra')
2014-06-22 20:18:31,599 DEBUG [sqlalchemy.engine.base.Engine][MainThread] Row ('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')

Traceback (most recent call last):
  File "../bin/initialize_myapp_db", line 9, in <module>
    load_entry_point('myapp==0.0', 'console_scripts', 'initialize_myapp_db')()
  File "/var/www/html/myapp/app/myapp/myapp/myapp/scripts/initializedb.py", line 44, in main
    DBSession.add(model)
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/orm/scoping.py", line 149, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/orm/session.py", line 1478, in add
    self._save_or_update_state(state)
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/orm/session.py", line 1490, in _save_or_update_state
    self._save_or_update_impl(state)
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/orm/session.py", line 1744, in _save_or_update_impl
    self._save_impl(state)
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/orm/session.py", line 1716, in _save_impl
    self._attach(state)
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/orm/session.py", line 1844, in _attach
    self.dispatch.after_attach(self, state.obj())
  File "/var/www/html/myapp/app/myapp/local/lib/python2.7/site-packages/SQLAlchemy-0.9.4-py2.7-linux-i686.egg/sqlalchemy/event/attr.py", line 257, in __call__
    fn(*args, **kw)
TypeError: unbound method after_attach() must be called with ZopeTransactionExtension instance as first argument (got Session instance instead)
  

Ответ №1:

DBSession в вашем случае это объект scoped_session . Чтобы получить фактический сеанс, вы должны вызвать его (что запускает вызов базовой фабрики сеансов).

 def main(argv=sys.argv): 
    ...
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)
    session = DBSession()
    ....
    session.add(model)
  

Ответ №2:

Ошибка означает, что вам нужен экземпляр DBSession, но класс. Я действительно не знаю пирамиду, но, возможно DBSession configure , вызов возвращает экземпляр? Если это так, вы должны зафиксировать возвращаемое значение и вызвать add его.

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

1. Большое спасибо! Я только что попробовал то, что вы сказали, но DBSession.configure() не возвращает ничего.

2. Можете ли вы опубликовать полную обратную трассировку?

3. Я только что отредактировал вопрос, чтобы добавить полную обратную трассировку.