Monday, 17 May 2021

Issues with add and delete rows with one to many relationship

Both of the tables include unique constraints. I have been strugling with this for some time now. What should the command be for adding and deleting?

Adding by doing

movie = Movie(title="transformers", director="mb")
movie2 = Movie(title="transformers2", director="mb")
genre = Genre(category="action")
db.session.add(movie)
db.session.add(movie2)
movie.genres.append(genre)
movie2.genres.append(genre)
db.session.commit()

Gives

(sqlite3.IntegrityError) UNIQUE constraint failed: genres.category
[SQL: INSERT INTO genres (category) VALUES (?)]
[parameters: ('action',)]
(Background on this error at: http://sqlalche.me/e/14/gkpj)

Deleting by doing

db.session.delete(Movie.query.filter_by(title="t1").first())
db.session.commit()

Does not delete

Whats expected:

  • Adding a new row if the title is not existing in Movie table, add a new row if the genre is not existing in Genre table and create a link in the Association table.

  • Deleting the title from Movie table and removing the link from Association table. Do nothing for genre.

Do I need to change my model?

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

class Config:
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:?charset=utf8'
    SQLALCHEMY_DATABASE_ECHO = False
    SQLALCHEMY_TRACK_MODIFICATIONS = 'False'
    FLASK_ENV = 'test'
    DEBUG = True


db = SQLAlchemy()
conf = Config()


def create_app():
    app = Flask(__name__)
    app.config.from_object(conf)
    db.init_app(app)

    return app


class Rating(db.Model):
    __tablename__ = 'ratings'
    id = db.Column(db.Integer, db.ForeignKey("movies.id"), primary_key=True,)
    rating = db.Column(db.String(4), index=True, nullable=False,)
    movie = db.relationship("Movie", back_populates="rating",)

    def __repr__(self):
        return '{}'.format(self.rating)


Association = db.Table('association',
                       db.Column('movies_id', db.Integer,
                                 db.ForeignKey('movies.id'), index=True,),
                       db.Column(
                           'genres_id',
                           db.Integer, db.ForeignKey('genres.id'), index=True,),
                       )


class Movie(db.Model):
    __tablename__ = 'movies'
    id = db.Column(db.Integer, primary_key=True, index=True,)
    title = db.Column(db.String(80), index=True, unique=True, nullable=False,)
    director = db.Column(db.String(30), primary_key=False,
                         unique=False, nullable=False)
    rating = db.relationship(
        "Rating", uselist=False, back_populates="movie"
    )
    genres = db.relationship(
        "Genre", secondary='association', backref=db.backref('movies'),
    )

    def __repr__(self):
        return '{}'.format(self.title)


class Genre(db.Model):
    __tablename__ = 'genres'
    id = db.Column(
        db.Integer,
        primary_key=True,
        index=True,
    )
    category = db.Column(
        db.String(80),
        index=True,
        unique=True,
        nullable=False,
    )

    def __repr__(self):
        return '{}'.format(self.category)


app = create_app()
context = app.app_context()
context.push()
db.create_all()

movie = Movie(title="transformers", director="mb")
rating = Rating(rating="5", movie=movie)
genre = Genre(category="action")
db.session.add_all([movie, rating])
movie.genres.append(genre)

try:
    db.session.commit()
    print("commit successfull")
except Exception as e:
    print(f"{e}")
    db.session.rollback()

movie2 = Movie(title="transformers2", director="mb")
rating = Rating(rating="5", movie=movie2)
genre2 = Genre.query.filter_by(category="action").first()
db.session.add_all([movie2, rating])
movie2.genres.append(genre2)

try:
    db.session.commit()
    print("commit successfull")
except Exception as e:
    print(f"{e}")
    db.session.rollback()

to_delete = Movie.query.filter_by(title="transformers").first()

try:
    db.session.delete(to_delete)
    db.session.commit()
    print("deletion successfull")
except Exception as e:
    print(f"{e}")
    db.session.rollback()

context.pop()

This results in a

commit successfull
commit successfull
Dependency rule tried to blank-out primary key column 'ratings.id' on instance '<Rating at 0x2022c81bdc8>'

EDIT proxy My old query which is not working when applying association proxy

query = (
        db.session
        .query(
            Rating.rating,
            Movie.title,
            Movie.director,
            db.func.GROUP_CONCAT(Genre.category, ", ").label("genres")
        )
        .select_from(Movie)
        .where(Rating.id == Movie.id)
        .join(Movie.genres)
        .group_by(
            Rating.rating,
            Movie.title,
            Movie.director,
        )
    )


from Issues with add and delete rows with one to many relationship

No comments:

Post a Comment