A continuación se muestra la forma correcta de realizar cambios en una instancia de modelo y enviarlos a la base de datos:
# get an instance of the 'Entry' model
entry = Entry.query.get(1)
# change the attribute of the instance; here the 'name' attribute is changed
entry.name = 'New name'
# now, commit your changes to the database; this will flush all changes
# in the current session to the database
db.session.commit()
SQLALCHEMY_COMMIT_ON_TEARDOWN
, ya que se considera dañino y también se elimina de los documentos. Consulte el registro de cambios para la versión 2.0
.
Editar: Si tienes dos objetos de sesión normal (creado usando sessionmaker()
) en lugar de sesión con ámbito , luego al llamar a db.session.add(entry)
el código anterior generará el error sqlalchemy.exc.InvalidRequestError: Object '' is already attached to session '2' (this is '3')
. Para comprender mejor la sesión de sqlalchemy, lea la siguiente sección
Gran diferencia entre la sesión con ámbito y la sesión normal
El objeto de sesión que construimos principalmente a partir de sessionmaker()
llamada y utilizada para comunicarse con nuestra base de datos es una sesión normal . Si llama a sessionmaker()
una segunda vez, obtendrá un nuevo objeto de sesión cuyos estados son independientes de la sesión anterior. Por ejemplo, supongamos que tenemos dos objetos de sesión construidos de la siguiente manera:
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
from sqlalchemy import create_engine
engine = create_engine('sqlite:///')
from sqlalchemy.orm import sessionmaker
session = sessionmaker()
session.configure(bind=engine)
Base.metadata.create_all(engine)
# Construct the first session object
s1 = session()
# Construct the second session object
s2 = session()
Entonces, no podremos agregar el mismo objeto Usuario a ambos s1
y s2
al mismo tiempo. En otras palabras, un objeto solo se puede adjuntar como máximo a un único objeto de sesión.
>>> jessica = User(name='Jessica')
>>> s1.add(jessica)
>>> s2.add(jessica)
Traceback (most recent call last):
......
sqlalchemy.exc.InvalidRequestError: Object '' is already attached to session '2' (this is '3')
Si los objetos de la sesión se recuperan de una scoped_session
objeto, sin embargo, entonces no tenemos tal problema desde la scoped_session
objeto mantiene un registro para el mismo objeto de sesión.
>>> session_factory = sessionmaker(bind=engine)
>>> session = scoped_session(session_factory)
>>> s1 = session()
>>> s2 = session()
>>> jessica = User(name='Jessica')
>>> s1.add(jessica)
>>> s2.add(jessica)
>>> s1 is s2
True
>>> s1.commit()
>>> s2.query(User).filter(User.name == 'Jessica').one()
Observe que s1
y s2
son el mismo objeto de sesión ya que ambos se recuperan de una scoped_session
objeto que mantiene una referencia al mismo objeto de sesión.
Consejos
Por lo tanto, trate de evitar crear más de una sesión normal objeto. Cree un objeto de la sesión y utilícelo en todas partes, desde declarar modelos hasta realizar consultas.