OK, here's a demonstration of the issue that this looks like, see if
cascade_backrefs solves your problem:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Hub(Base):
__tablename__ = 'hub'
id = Column(Integer, primary_key=True)
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
hub_id = Column(ForeignKey('hub.id'))
hub = relationship("Hub", backref=backref("tags"))
# with cascade_backrefs set, the Tag object will not be automatically
# cascaded into the Session when Tag(hub=some_hub) is called; see below
# hub = relationship("Hub", backref=backref("tags",
cascade_backrefs=False))
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
# 1. pre-existing Tag object in the database
s.add(Tag(id=1))
# 2. commit; this expires all state in the Session and we don't see
# id=1 in memory anymore.
s.commit()
# 3. new Hub
hub = Hub(id=1)
# 4. merged_hub is in the pending session state
merged_hub = s.merge(hub)
# assert pending state; not INSERTed yet
assert merged_hub in s.new
# 5. create a Tag, referencing the Hub. The backref assigns the Tag
# to the merged_hub.tags collection, which then *adds* the Tag into the
# session as a *new, non-merged object*. If we use the cascade_backrefs
# flag, this effect does not occur. Documentation at:
# http://docs.sqlalchemy.org/en/rel_1_0/orm/cascades.html#backref-cascade
tag = Tag(id=1, hub=merged_hub)
# 6a. if we called flush() here, we'd get the same error...
# s.flush()
# 6b. ... since the tag object is *in the session*
assert tag in s.new
# 7. now we get to the merge part here, which looks in the DB for
# tag id=1, does an autoflush, raises error. We know the error is here
# due to the stack trace as well as that it refers to "autoflush".
merged_tag = s.merge(tag)
s.commit()
On 03/26/2016 01:27 PM, Ricardo Champa wrote:
I tried to simplify the code as much as i can. I did another simple
sample of code wihtout columns and relationships (adding and removing)
and seems working fine. There is an error with my code above but I cant
figure out what.
El sábado, 26 de marzo de 2016, 18:05:23 (UTC+1), Mike Bayer escribió:
On 03/26/2016 12:51 PM, Ricardo Champa wrote:
> Sorry, You are right.
This seems like something I saw recently, you might want to check if
nuevo_tag isn't already in the session. But I can't re-identify the
problem without a much more concise and runnable example (remove all
columns, directives, and relationships not part of the problem, show
use
of Session, etc).
Again the best way to make this a one-email exchange is to follow the
guidelines in the http://stackoverflow.com/help/mcve
<http://stackoverflow.com/help/mcve> document.
>
> I want to perform and *insert or update* but I always get this
error:
>
> sqlalchemy.exc.IntegrityError: (raised as a result of
Query-invoked
> autoflush; consider using a session.no_autoflush block if
this flush
> is occurring prematurely) (pymysql.err.IntegrityError) (1062,
> "Duplicate entry
>
'\\x11\\x0E\\x84\\x00\\xE2\\x9B\\x11\\xD4\\xA7\\x16DfUD\\x00\\x0D'
> for key 'PRIMARY'") [SQL: 'INSERT INTO tags (guid_tag,
id_project,
> guid_item, type, created_at, updated_at) VALUES (%(guid_tag)s,
> %(id_project)s, %(guid_item)s, %(type)s, %(created_at)s,
> %(updated_at)s)'] [parameters: {'guid_item':
> b'\x11\x0e\x84\x00\xe2\x9b\x11\xd4\xa7\x16DfUD\x00"',
'id_project':
> 1, 'created_at': '2016-03-22 06:00:01', 'updated_at':
'2016-03-23
> 06:21:31', 'type': 0, 'guid_tag':
> b'\x11\x0e\x84\x00\xe2\x9b\x11\xd4\xa7\x16DfUD\x00\r'}]
>
>
> There is a row in DB that has the same PK, so I expect merge
bring that
> record from DB but instead of it perform a new insert as error
message
> shows.
>
> The whole definition of clases and models.
>
> |classItem(db.Model):__tablename__ ="items"# id_item =
> db.Column(db.Integer, autoincrement=True, primary_key=True)guid_item
> =db.Column(db.BINARY(16),primary_key=True)id_project
> =db.Column(db.Integer,db.ForeignKey("projects.id_project"))type
> =db.Column(db.Integer)name
> =db.Column(db.String(50),nullable=False,index=True)created_at
> =db.Column(db.DateTime)updated_at
=db.Column(db.DateTime)__mapper_args__
>
={'polymorphic_identity':'items','polymorphic_on':type,'with_polymorphic':'*'}__table_args__
>
=(db.UniqueConstraint('name','id_project',name='_unique_name_project'),)def__init__(self,creado_en=None):self.created_at
> =creado_en self.updated_at =creado_en classHub(Item):__tablename__
> ="hubs"__mapper_args__
> ={'polymorphic_identity':TYPE_HUB,'with_polymorphic':'*'}guid_hub
>
=db.Column(db.BINARY(16),db.ForeignKey(Item.guid_item),primary_key=True)location
> =db.Column(db.String(50))comments
>
=db.Column(db.String(128))def__init__(self,guid_hub=None,nombre=None,location=None,comments=None,id_project=None,creado_en=None,actualizado_en=None):self.type
> =TYPE_HUB self.guid_item =guid_hub self.guid_hub =guid_hub
self.name <http://self.name>
> =nombre self.id_project =id_project self.location =location
> self.comments =comments self.created_at =creado_en self.updated_at
> =actualizado_en classTag(db.Model):__tablename__ ="tags"guid_tag
> =db.Column(db.BINARY(16),primary_key=True)id_project
> =db.Column(db.Integer,db.ForeignKey("projects.id_project"))guid_item
> =db.Column(db.BINARY(16),db.ForeignKey("items.guid_item"))project
>
=db.relationship(Proyecto,backref=db.backref('list_tags',lazy='dynamic'))item
>
=db.relationship(Item,backref=db.backref('list_tags',lazy='joined'))type
>
=db.Column(db.Integer)#(0,hub);(1,cable);(2,pipe);(3,electrical_pipes)created_at
> =db.Column(db.DateTime)updated_at
>
=db.Column(db.DateTime)def__init__(self,guid_tag,project,item,type,created_at,updated_at):#
> self.guid_item = guid_tagself.guid_tag =guid_tag self.project
=project
> self.item =item self.type =type self.created_at =created_at
> self.updated_at =updated_at|
>
>
> El sábado, 26 de marzo de 2016, 17:26:04 (UTC+1), Mike Bayer
escribió:
>
>
>
> On 03/26/2016 12:06 PM, Ricardo Champa wrote:
> > AFAIK merge performs and |insert or update| so what I'm
doing is
> pretty
> > simple. There is a relation of 1 to N between Hubs and
Tags. So
> when I
> > try to make a merge on tag and hub, hub goes well and load
from
> DB the
> > existent hub and make an update, but fails when
> > |db.session.merge(nuevo_tag)| is executed throwing an
exception
> because
> > behind the scenes is try to make an insert, even if the tag
> previously
> > exist. What I did wrong?
> >
> > |nuevo_hub
> >
>
=Hub(guid_hub,name,location,comments,id_project,creado_en,actualizado_en)merged_hub
>
> > =db.session.merge(nuevo_hub)#db.session.commit() # If I
use this
> line
> > tags perform an insert.nuevo_tag
> >
>
=Tag(guid_tag,project,merged_hub,TYPE_HUB,creado_en,actualizado_en)merged_tag
>
> > =db.session.merge(nuevo_tag)db.session.commit()|
>
> nothing seems wrong with the small amount code pictured and
also i
> don't
> know what exception you are getting, nor do I have enough
context to
> understand the issue in general, so please provide minimal,
working
> mappings and a demonstration per the guidelines at
> http://stackoverflow.com/help/mcve
<http://stackoverflow.com/help/mcve>
> <http://stackoverflow.com/help/mcve
<http://stackoverflow.com/help/mcve>>, thanks!
>
>
> >
> > --
> > You received this message because you are subscribed to
the Google
> > Groups "sqlalchemy" group.
> > To unsubscribe from this group and stop receiving emails
from it,
> send
> > an email to [email protected] <javascript:>
> > <mailto:[email protected]
<javascript:> <javascript:>>.
> > To post to this group, send email to
[email protected]
> <javascript:>
> > <mailto:[email protected] <javascript:>>.
> > Visit this group at
https://groups.google.com/group/sqlalchemy
<https://groups.google.com/group/sqlalchemy>
> <https://groups.google.com/group/sqlalchemy
<https://groups.google.com/group/sqlalchemy>>.
> > For more options, visit https://groups.google.com/d/optout
<https://groups.google.com/d/optout>
> <https://groups.google.com/d/optout
<https://groups.google.com/d/optout>>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it,
send
> an email to [email protected] <javascript:>
> <mailto:[email protected] <javascript:>>.
> To post to this group, send email to [email protected]
<javascript:>
> <mailto:[email protected] <javascript:>>.
> Visit this group at https://groups.google.com/group/sqlalchemy
<https://groups.google.com/group/sqlalchemy>.
> For more options, visit https://groups.google.com/d/optout
<https://groups.google.com/d/optout>.
--
You received this message because you are subscribed to the Google
Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to [email protected]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[email protected]>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.