My apologies, I finally stumbled upon an answer in SQLAlchemy docs ...
http://docs.sqlalchemy.org/en/rel_1_0/orm/basic_relationships.html#many-to-many
... where they clearly define the difference:
Many to many adds a table of relationships between the two classes.
association_table = Table('association', Base.metadata, Column('left_id', Integer, ForeignKey('left.id')), Column('right_id', Integer, ForeignKey('right.id')) )
The association object template is a many-to-many option: it is used when your association table contains additional columns, in addition to those that are foreign keys for the left and right tables. Instead of using a secondary argument, you map the new class directly to the association table.
class Association(Base): __tablename__ = 'association' left_id = Column(Integer, ForeignKey('left.id'), primary_key=True) right_id = Column(Integer, ForeignKey('right.id'), primary_key=True) extra_data = Column(String(50)) left = relationship('Left', backref=backref('right_association')) right = relationship('Right', backref=backref('left_association'))
Where "Right" and "Left" are usually defined tables:
class Left(Base): __tablename__ = 'left' id = Column(Integer, primary_key = True) ... class Right(Base): __tablename__ = 'right' id = Column(Integer, primary_key = True) ...
Thus, this is basically creating an association object to reference this additional information if you need to save something in the association, otherwise there is no need to use the ORM layer, and you can just create an association table.