2016-05-09 4 views
2

Mit dem Beispiel von documentation versuche ich, vorhandene untergeordnete Elemente an ein neues übergeordnetes Element anzuhängen. Zum einen habe ich versucht, das Beispiel:Anhängen von zwei oder mehr vorhandenen untergeordneten Elementen an Ursache IntegrityError, Query-aufgerufene autoflush

>>> p = models.Parent() 
>>> a1 = models.Association(extra_data='data1') 
>>> a2 = models.Association(extra_data='data2') 
>>> a1.child = models.Child() 
>>> a2.child = models.Child() 
>>> p.children.append(a1) 
>>> p.children.append(a2) 
>>> db.session.add(p) 
>>> db.session.commit() # OK! 

Jetzt habe ich zwei Kinder und ein Elternteil in meinem DB. Dann habe ich versucht:

>>> p2 = models.Parent() 
>>> a1 = models.Association(extra_data='data3') 
>>> a2 = models.Association(extra_data='data4') 
>>> a1.child = models.Child.query.get(1) 
>>> a2.child = models.Child.query.get(2) # Oops! 

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    ✂-----<...>------- 
    File "/home/boss/codes/python_projects/c/flaskenv/lib/python3.5/site-packages/MySQLdb/connections.py", line 280, in query 
_mysql.connection.query(self, query) 
sqlalchemy.exc.IntegrityError: (raised as a result of Query-invoked 
autoflush; consider using a session.no_autoflush block if this flush 
is occurring prematurely) (_mysql_exceptions.IntegrityError) (1364, 
"Field 'left_id' doesn't have a default value") [SQL: 'INSERT INTO 
association (right_id, extra_data) VALUES (%s, %s)'] [parameters: (1, 
'data3')] 

# Let's continue 
>>> db.session.rollback() 
>>> a1.child 
<app.models.Child object at 0x7f7bac39ffd0> 
>>> a2.child 

>>> a2.child = models.Child.query.get(2) 
>>> a2.child 
<app.models.Child object at 0x7f7bac2465c0> 
>>> p2.children.append(a1) 
>>> p2.children.append(a2) 
>>> db.session.add(p2) 
>>> db.session.commit() # OK! 
>>> 

Was mache ich falsch? Hinweis: Ich verwende nicht Autocommit und ich habe Kinder an Eltern anhängen und fügen Sie sie in DB nach session.rollback().

Fehler Erklärung verweist mich auf "in Betracht ziehen, mit einem session.no_autoflush-Block", aber ich brauche eine weitere Klärung, wie dieser Mechanismus funktioniert, und könnte es möglicherweise zu weiteren Fehlern oder Sicherheitsrisiken führen, wenn ich Autoflush deaktivieren.

+0

In Verbindung stehend: https://stackoverflow.com/questions/48188660/inserting-data-in-anassociation-table-using-sqlalchemy –

Antwort

0

Es scheint, wie ich etwas Abhilfe gefunden habe:
Verwendung session.no_autoflush (als Fehler Erklärung zu tun, bietet):

>>> p2 = models.Parent() 
>>> a1 = models.Association(extra_data='data5') 
>>> a2 = models.Association(extra_data='data6') 
>>> with db.session.no_autoflush: 
...  a1.child = models.Child.query.get(1) 
...  a2.child = models.Child.query.get(2) 
... 
>>> p2.children.append(a1) 
>>> p2.children.append(a2) 
>>> db.session.add(p2) 
>>> db.session.commit() 
>>> 

Aber wenn Sie nicht wollen, mit flush Sachen langweilen, nur die one-by-one Kinder hängen sie wie folgt vor:

>>> p2 = models.Parent() 
>>> a1 = models.Association(extra_data='data9') 
>>> a2 = models.Association(extra_data='data10') 
>>> a1.child = models.Child.query.get(1) 
>>> p2.children.append(a1) 
>>> a2.child = models.Child.query.get(2) 
>>> p2.children.append(a2) 
>>> db.session.add(p2) 
>>> db.session.commit() 

wie dem auch sei, delails von Autoflushing Mechanismus und Fehler es sind, müssen noch mehr Erklärung dazu führen, glaube ich.

Verwandte Themen