Pourquoi une requête appeler une auto-flush dans SQLAlchemy?
Le code que vous voyez ci-dessus est juste un exemple, mais il fonctionne à reproduire cette erreur:
sqlalchemy.exc.IntegrityError: (raised as a result of Query-invoked autoflush;
consider using a session.no_autoflush block if this flush is occurring prematurely)
(sqlite3.IntegrityError) NOT NULL constraint failed: X.nn
[SQL: 'INSERT INTO "X" (nn, val) VALUES (?, ?)'] [parameters: (None, 1)]
Une instance mappée est tout de même ajouté une session. L'instance veut savoir (ce qui signifie la requête sur la base de données) si d'autres instances de son propre type existe avoir les mêmes valeurs. Il y a un deuxième attribut/colonne (_nn
). Il est alors précisé à NOT NULL
. Mais par défaut il est NULL
.
Lorsque l'instance (comme dans l'exemple) est toujours ajouté à la session de l'appel à query.one()
appeler une auto-flush. Rincer créer un INSERT
qui tente de stocker l'instance. Cela échoue, car _nn
est toujours nulle et viole les NOT NULL
contrainte.
Qu'est ce que je comprends actuellement.
Mais la question est pourquoi est-il invoquer une auto-flush? Puis-je bloquer?
#!/usr/bin/env python3
import os.path
import os
import sqlalchemy as sa
import sqlalchemy.orm as sao
import sqlalchemy.ext.declarative as sad
from sqlalchemy_utils import create_database
_Base = sad.declarative_base()
session = None
class X(_Base):
__tablename__ = 'X'
_oid = sa.Column('oid', sa.Integer, primary_key=True)
_nn = sa.Column('nn', sa.Integer, nullable=False) # NOT NULL!
_val = sa.Column('val', sa.Integer)
def __init__(self, val):
self._val = val
def test(self, session):
q = session.query(X).filter(X._val == self._val)
x = q.one()
print('x={}'.format(x))
dbfile = 'x.db'
def _create_database():
if os.path.exists(dbfile):
os.remove(dbfile)
engine = sa.create_engine('sqlite:///{}'.format(dbfile), echo=True)
create_database(engine.url)
_Base.metadata.create_all(engine)
return sao.sessionmaker(bind=engine)()
if __name__ == '__main__':
session = _create_database()
for val in range(3):
x = X(val)
x._nn = 0
session.add(x)
session.commit()
x = X(1)
session.add(x)
x.test(session)
Bien sûr, une solution serait de pas ajouter une instance de la séance, avant de query.one()
a été appelé. De ce travail. Mais dans ma vraie (mais complexe pour cette question) de cas d'utilisation, il n'est pas une solution sympa.
OriginalL'auteur buhtz | 2015-10-03
Vous devez vous connecter pour publier un commentaire.
Comment désactiver autoflush fonctionnalité:
Temporaire: vous pouvez utiliser no_autoflush gestionnaire de contexte sur l'extrait de code lorsque vous interrogez la base de données, c'est à dire dans
X.test
méthode:Session-large: il suffit de passer
autoflush=False
à votre sessionmaker:Dans la réponse il y a un lien vers les docs où autoflush fonctionnalité est expliquée. Si quelque chose reste difficile vous feriez mieux de poser des question.
Il s'avère que je n'étais pas à l'appel de
db.commit()
quand je devais le faire, de sorte qu'il m'a fait penser à laautoflush
ne fonctionnait pas comme prévu, donc ma question était fondée sur une erreur.citation de la
no_autoflush
section de la documentation liée ci-dessus: "Ceci est utile lors de l'initialisation d'une série d'objets qui impliquent existant requêtes de base de données, où l'objet inachevé ne devrait pas encore être vidées."OriginalL'auteur Palasaty