if you are mapping ORM classes to the same table that is also used as the 
"secondary" table in a relationship() that can lead to the ORM inserting more 
than one row for that table.   based on the name "foo_bar" I would imagine 
something like this might be going on.   


> 
> Pls tell how to delete instance with repeated elements in relation.

So assuming this is a development database where you can start all over again, 
the approach here is to *never have* repeated elements in a relationship.  When 
you make a "secondary" table, make sure you set the columns that refer to the 
related tables inside of a constraint, such as UNIQUE constraint, or more 
commonly make them the primary key.  I should add this to the docs at 
https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html#many-to-many as 
this seems to not be mentioned:

association_table = Table('association', Base.metadata,
    Column('left_id', Integer, ForeignKey('left.id'), primary_key=True),
    Column('right_id', Integer, ForeignKey('right.id'), primary_key=True)
)

class Parent(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    children = relationship("Child",
                    secondary=association_table)

class Child(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)





> 
> P.S. It seems the error to be raised implicit, because "ONLY 2 were matched"
> понедельник, 19 июля 2021 г. в 16:22:01 UTC+3, Mike Bayer: 
>> __
>> This is all expected behavior, the main reason you're having problems is 
>> that you are using multiple sessions and mixing their results together.    
>> If you need to do this, there are few approaches, the most basic being to 
>> use the merge() method: 
>> https://docs.sqlalchemy.org/en/14/orm/session_api.html?highlight=session%20merge#sqlalchemy.orm.Session.merge
>> 
>> however the main issue is that you are mixing results from multiple 
>> sessions, which in the vast majority of cases is unnecessary.  The session 
>> corresponds to working in a single transaction at a time, and you should 
>> normally be able to complete all the work you have for a particular 
>> operation within that single scope.   
>> 
>> On Mon, Jul 19, 2021, at 8:31 AM, Evgenii wrote:
>>> 
>>> 
>>> 
>>> 
>>> Hello!
>>> I’m using many-to-many relation, and this relationship `bar_list` must have 
>>> list of
>>> instances. Some of them can be repeated (ex. `[inst1, inst2, inst1]`).
>>> I attach very simplified code there (all of database interaction is hidden
>>> under the hood, user accesses database at top level, but this example 
>>> reflects
>>> my problem).
>>> 
>>> 
>>> `foo_bar_association = Table(
>>>     'foo_bar', Base.metadata,
>>>     Column('foo_id', Integer, ForeignKey('foo.id')),
>>>     Column('bar_id', Integer, ForeignKey('bar.id'))
>>> )
>>> 
>>> *class* *FooTable*(Base):
>>>     __tablename__ = 'foo'
>>> 
>>>     id = Column(Integer, primary_key=*True*)
>>>     type = Column(String, nullable=*False*)
>>> 
>>>     bar_list = relationship('BarTable',
>>>                             secondary=foo_bar_association,
>>>                             lazy='subquery')
>>> 
>>>     *def* *__init__*(self, type_, bar_list):
>>>         self.type = type_
>>>         self.bar_list = bar_list
>>> 
>>> *class* *BarTable*(Base):
>>>     __tablename__ = 'bar'
>>> 
>>>     id = Column(Integer, primary_key=*True*)
>>>     name = Column(String, nullable=*False*)
>>> 
>>>     *def* *__init__*(self, name):
>>>         self.name = name
`
>>> 
>>> 
>>> When I pass two exact instances `[bar_one, bar_same_one]`(as a 
>>> relationship) have to be related (before `session.close()`) to different 
>>> sessions I have this error:
>>> `sqlalchemy.exc.InvalidRequestError: Can't attach instance another instance 
>>> with key is already present in this session.`
>>> 
>>> 
>>> `*with* Session() *as* session:
>>>     bar_one = session.query(BarTable).get(1)
>>> 
>>> *with* Session() *as* session:
>>>     bar_same_one = session.query(BarTable).get(1)
>>> 
>>> *with* Session() *as* session:
>>>     foo = FooTable('some_type', [bar_one, bar_same_one])
>>>     session.add(foo)
>>>     session.commit()
`
>>> But I don’t have any error after I create instances in same session:
>>> 
>>> `*with* Session() *as* session:
>>>     bar_one = session.query(BarTable).get(1)
>>>     bar_same_one = session.query(BarTable).get(1)
>>> 
>>> *with* Session() *as* session:
>>>     foo = FooTable('some_type', [bar_one, bar_same_one])
>>>     session.add(foo)
>>>     session.commit()
`
>>> And after:
>>> 
>>> `*with* Session() *as* session:
>>>     foo = FooTable('some_type', [bar_one, bar_one])
>>>     session.add(foo)
>>>     session.commit()
`
>>> I can make a work around:
>>> 
>>>  1. Find unique instances in `bar_list` and replace not unique with unique
>>> or
>>>  2. Get all `bar_list` ids and get all instances in same session before 
>>> adding
>>> foo instance.
>>> But both of them are not pure python way and seems to be complicated and 
>>> ugly.
>>> I hope there is simple alchemy solution (as adding simple attribute in 
>>> relationship)
>>> `Python 3.7.10
>>> SQLAlchemy==1.4.15
`
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> -- 
>>> SQLAlchemy - 
>>> The Python SQL Toolkit and Object Relational Mapper
>>>  
>>> http://www.sqlalchemy.org/
>>>  
>>> To post example code, please provide an MCVE: Minimal, Complete, and 
>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
>>> description.
>>> --- 
>>> 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 sqlalchemy+...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/sqlalchemy/8205e75c-6d78-4123-842b-4e342ad244een%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/sqlalchemy/8205e75c-6d78-4123-842b-4e342ad244een%40googlegroups.com?utm_medium=email&utm_source=footer>.
>> 
> 
> 
> -- 
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> 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 sqlalchemy+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/64a84806-e010-4dd4-b27c-9ff62f80faa0n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/64a84806-e010-4dd4-b27c-9ff62f80faa0n%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/6120a1b1-2d48-45df-8fa5-5a7b1f6ad449%40www.fastmail.com.

Reply via email to