sqlalchemy: delete() on m:n-relationship

Wolfgang Meiners WolfgangMeiners01 at web.de
Sat May 19 09:25:30 EDT 2012


Hi all,

i dont understand, how sqlalchemy deletes from m:n relationships.

Maybe, someone can explain to me, how to delete in the following program:

(pyhton3, sqlalchemy 0.7.0)

=====================================================================
> #!/usr/bin/env python3
> # -*- coding: utf-8 -*-
> 
> '''
> Created on 19.05.2012
> 
> @author: wolfgang
> 
> '''
> 
> from sqlalchemy import *
> 
> from sqlalchemy.orm.session import sessionmaker
> from sqlalchemy.orm import relationship, backref
> from sqlalchemy.ext.declarative import declarative_base
> 
> 
> Base = declarative_base()
> 
> class Book(Base):
>     __tablename__='books'
>     
>     def __init__(self, title, authors):
>         # here authors is a list of items of type Autor
>         self.title = title
>         for author in authors:
>             self.authors.append(author)
>     
>     bid = Column(Integer, primary_key=True)
>     title = Column(String, index=True)
>     
>     authors = relationship('Author', secondary='author_book', 
>                            backref=backref('books', order_by='Book.title', cascade='all, delete'),
>                            cascade='all, delete')
>     
> class Author(Base):
>     __tablename__ = 'authors'
>     
>     def __init__(self, name):
>         self.name = name
>     
>     aid = Column(Integer, primary_key=True)
>     name = Column(String, index=True)
>     
> 
> # Association table between authors and books:
> author_book = Table('author_book', Base.metadata,
>                     Column('aid', Integer, ForeignKey('authors.aid'), primary_key=True),
>                     Column('bid', Integer, ForeignKey('books.bid'), primary_key=True))
> 
> 
> class DB:
>     def __init__(self, dbname=None, echo=False):
>         self.dbname = dbname if dbname else ':memory:'
>         self.dbfile = 'sqlite:///{db}'.format(db=self.dbname)
>         self.engine = create_engine(self.dbfile)
>         Base.metadata.create_all(self.engine)
>         self.Session = sessionmaker(self.engine)
> 
> def find_or_create_author(session, name):
>     qauthor = session.query(Author).filter_by(name=name)
>     if qauthor.count() == 0:
>         session.add(Author(name=name))
>     return qauthor.one()
>         
> if __name__ == '__main__':
> 
>     db = DB(dbname='booksdb.sqlite', echo=True)
>     session = db.Session()
>     
>     # insert 4 books into db
>     session.add_all([Book(title='Title a',
>                           authors=[find_or_create_author(session, name='Author 1'),
>                                    find_or_create_author(session, name='Author 2')]),
>                      Book(title='Title b',
>                           authors=[find_or_create_author(session, name='Author 1'),
>                                    find_or_create_author(session, name='Author 2')]),
>                      Book(title='Title c',
>                           authors=[find_or_create_author(session, name='Author 3'),
>                                    find_or_create_author(session, name='Author 4')]),
>                      Book(title='Title d',
>                           authors=[find_or_create_author(session, name='Author 3'),
>                                    find_or_create_author(session, name='Author 4')])])
>     
>     session.commit()
>     
>     # At this point there are 4 book in db, the first 2 written by Author 1 and Author 2,
>     # the last 2 written by Author 3 and Author 4.
>     # Now, i delete books with bid == 1 and bid == 3:
>     
>     book1 = session.query(Book).filter_by(bid=1).one()
>     session.delete(book1)
>     
>     session.query(Book).filter_by(bid=3).delete()
>     
>     session.commit()
>     
>     # The first query deletes to much: Title b is related to Author 1 and Author 2
>     # this relation has dissapeared from the db
>     
>     # The last query deletes to less: There is no Title 3, but the entries 
>     # of this book remain in the associationtable.
>     
>     # How is this done right?
==========================================================================================

after i run this program, the contents of booksdb.sqlite has the
following data:

$ sqlite3 booksdb.sqlite
SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from author_book;
3|3
4|3
3|4
4|4

sqlite> select * from
   ...> books natural inner join author_book
   ...> natural inner join authors;
4|Title d|3|Author 3
4|Title d|4|Author 4

which means, association between Title b and ist authors is lost,
information on Title c is still in author_book table.

Thank you for any help

Wolfgang



More information about the Python-list mailing list