Search code examples
pythonsqlalchemymany-to-manyflask-sqlalchemy

Data added through a many-to-many relationship on one Model instance gets attached to many instances


I have a simple many-to-many relationship that looks like this:

tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('page_id', db.Integer, db.ForeignKey('page.id'))
)

class Page(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(128))
    tags = db.relationship('Tag', secondary=tags,
        backref=db.backref('pages', lazy='dynamic'))

class Tag(db.Model):
    name = db.Column(db.String(128))
    id = db.Column(db.Integer, primary_key=True)

I have some data in yaml format:

Page 1:
  - tag1
  - tag2
Page 2:
  - tag3
  - tag4

Which when loaded looks like this:

data = {'Page 1': ['tag1', 'tag2'], 'Page 2': ['tag3', 'tag4']}

When I try to insert it into the database:

def load_data():
    for page_title in data:
        p = (Page.query.filter_by(title=page_title).first() or
            Page(
                title=page_title
            )
        )

        for tag_name in data[page_title]:
            t = (Tag.query.filter_by(name=tag_name).first() or
                Tag(
                    name=tag_name
                )
            )

            p.tags.append(t)
        db.session.add(p)
        db.session.commit()

And then dump it out again:

def dump_data():
    pages = Page.query.all()
    for p in pages:
        print p.title + ":"
        for t in p.tags:
            print "  - " + t.name

The tags are getting associated with multiple pages:

Page 1:
  - tag1
  - tag3
  - tag4
  - tag2
Page 2:
  - tag2
  - tag3
  - tag4

I am at a loss as to why. (It isn't the dump method, as I've confirmed the relationships are present in the DB through flask-admin.) Any help gratefully received!

(I should add that I'm new to Python, Flask & Flask-SQLAalchemy, so am making this up as I go along! But I've read around this and tried multiple alternatives to no avail.)


Solution

  • It proved to be something really simple, that took ages to discover - I had at some point deleted the Page and Tag data, but not their associations, so new data was getting both old and new associations!