diff --git a/loan.py b/loan.py index 7a49d89..d2a4241 100644 --- a/loan.py +++ b/loan.py @@ -90,9 +90,10 @@ def loan(id): loan = Loan.query.get(id) try: if 'delete' in request.form: - st.SetMessage( f"Successfully deleted (id={loan.id}, who={loan.firsnames} {loan.surname})" ) + st.SetMessage( f"Successfully deleted (id={loan.id}, who={loan.firstnames} {loan.surname})" ) # fall back to direct sql because loan.py is imported before Book_Loan_Link exists - db.engine.execute( f"delete from book_loan_link where loan_id = {loan.id}" ) + with db.engine.connect() as conn: + conn.exec_driver_sql( f"delete from book_loan_link where loan_id = {loan.id}" ) loan = Loan.query.filter(Loan.id==id).delete() if 'submit' in request.form: st.SetMessage( f"Successfully Updated Loan (id={id})" ) diff --git a/main.py b/main.py index 4bb9fcb..ba3b21f 100644 --- a/main.py +++ b/main.py @@ -246,7 +246,8 @@ def GetBookIdFromBookSubBookLinkByIdAndSubBookNum( book_id, sub_book_num ): # Just select sub_book data and hand add it to the books object, and use it in jinja2 to indent/order the books/sub books # This data is used to sort/indent subbooks def AddSubs(books): - subs = db.engine.execute ( "select * from book_sub_book_link" ) + with db.engine.connect() as conn: + subs = conn.exec_driver_sql( "select * from book_sub_book_link" ) for row in subs: index = next((i for i, item in enumerate(books) if item.id == row.sub_book_id), -1) if index == -1: @@ -257,7 +258,8 @@ def AddSubs(books): # HACK: Couldn't work out ORM to excluded sub_book self-ref, so using basic python # loop to remove sub_books from list def RemSubs(books): - subs = db.engine.execute ( "select * from book_sub_book_link" ) + with db.engine.connect() as conn: + subs = conn.exec_driver_sql( "select * from book_sub_book_link" ) for row in subs: for i, item in enumerate(books): if item.id == row.sub_book_id: @@ -455,7 +457,8 @@ def subbooks_for_book(id): #################################### # force sub books for jinja2 to be able to use (ORM is not giving all the details #################################### - subs = db.engine.execute ( "select bsb.book_id, bsb.sub_book_id, bsb.sub_book_num, book.title, \ + with db.engine.connect() as conn: + subs = conn.exec_driver_sql( "select bsb.book_id, bsb.sub_book_id, bsb.sub_book_num, book.title, \ r.name as rating, book.year_published, book.notes, \ bal.author_id as author_id, author.surname||', '||author.firstnames as author \ from book_sub_book_link bsb, book, book_author_link bal, author, rating r\ @@ -471,14 +474,27 @@ def subbooks_for_book(id): return render_template("subbooks_for_book.html", sub_books=sub_book, s2=subs ) ################################################################################ -# /remove_sub_book -> POST -> removes this subbook from parent +# /remove_subbook -> POST -> removes this subbook from parent, takes you back to # /books (or /book/ -- if you added a sub-book of parent_id ################################################################################ @app.route("/remove_subbook", methods=["POST"]) @login_required def remove_sub_book(): + parent_book_id=request.form['rem_sub_parent_id'] + sub_book_id=request.form['rem_sub_sub_book_id'] + sub_book=Book.query.get( sub_book_id ) + remember=Book_Sub_Book_Link.query.filter(Book_Sub_Book_Link.book_id==parent_book_id, Book_Sub_Book_Link.sub_book_id==sub_book_id ).one() + orig_sub_book_num=remember.sub_book_num try: - db.engine.execute("delete from book_sub_book_link where book_id = {} and sub_book_id = {}".format( request.form['rem_sub_parent_id'], request.form['rem_sub_sub_book_id']) ) + # delete book-subbook link for this subbook + db.session.delete(remember) + # need to reorder old sub_book_nums to remove the new gap we created + bsbls=Book_Sub_Book_Link.query.filter(Book_Sub_Book_Link.book_id==parent_book_id, Book_Sub_Book_Link.sub_book_num>=orig_sub_book_num ).all() + for sb in bsbls: + sb.sub_book_num=sb.sub_book_num-1 + + # now remove subbook itself + db.session.delete(sub_book) db.session.commit() return redirect( '/book/{}'.format(request.form['rem_sub_parent_id']) ) except SQLAlchemyError as e: @@ -530,13 +546,15 @@ def new_book(): db.session.commit() # this is a sub-book we have added if 'parent_id' in request.form: - db.engine.execute( "insert into book_sub_book_link ( book_id, sub_book_id, sub_book_num ) values ( {}, {}, (select COALESCE(MAX(sub_book_num),0)+1 from book_sub_book_link where book_id = {}) )".format( request.form['parent_id'], book.id, request.form['parent_id'] ) ) + with db.engine.connect() as conn: + conn.exec_driver_sql( "insert into book_sub_book_link ( book_id, sub_book_id, sub_book_num ) values ( {}, {}, (select COALESCE(MAX(sub_book_num),0)+1 from book_sub_book_link where book_id = {}) )".format( request.form['parent_id'], book.id, request.form['parent_id'] ) ) parent=Book.query.get(request.form['parent_id']) if len(parent.series) > 0: # we have added a sub-book to something in a series # already, so add a bsl for the next book_num for s in parent.bsl: - db.engine.execute( "insert into book_series_link ( series_id, book_id, book_num ) values ( {}, {}, (select COALESCE(MAX(book_num),0)+1 from book_series_link where series_id={}) )".format( s.series_id, book.id, s.series_id ) ) + with db.engine.connect() as conn: + conn.exec_driver_sql( "insert into book_series_link ( series_id, book_id, book_num ) values ( {}, {}, (select COALESCE(MAX(book_num),0)+1 from book_series_link where series_id={}) )".format( s.series_id, book.id, s.series_id ) ) db.session.commit() st.SetMessage( "Created new Book ({})".format(book.title) ) cnt=1 @@ -544,7 +562,8 @@ def new_book(): if 'bsl-book_id-' in field and field != 'bsl-book_id-NUM': cnt=int(re.findall( '\d+', field )[0]) sql="insert into book_series_link (book_id, series_id, book_num) values ( {}, {}, {} )".format( book.id, request.form['bsl-series_id-{}'.format(cnt)], request.form['bsl-book_num-{}'.format(cnt)]) - db.engine.execute( sql ) + with db.engine.connect() as conn: + conn.exec_driver_sql( sql ) cnt=cnt+1 return redirect( '/book/{}'.format(book.id) ) else: @@ -660,7 +679,8 @@ def book(id): CheckSeriesChange={'type':'child', 'pid': book.parent[0].id, 'bid': book.id, 'removing_series': removing_series } else: # delete all bsls - db.engine.execute("delete from book_series_link where book_id = {}".format( book.id ) ) + with db.engine.connect() as conn: + conn.exec_driver_sql( "delete from book_series_link where book_id = {}".format( book.id ) ) cnt=1 for field in request.form: @@ -670,7 +690,8 @@ def book(id): sql="insert into book_series_link (book_id, series_id) values ( {}, {} )".format( request.form['bsl-book_id-{}'.format(cnt)], request.form['bsl-series_id-{}'.format(cnt)] ) else: sql="insert into book_series_link (book_id, series_id, book_num) values ( {}, {}, {} )".format( request.form['bsl-book_id-{}'.format(cnt)], request.form['bsl-series_id-{}'.format(cnt)], request.form['bsl-book_num-{}'.format(cnt)]) - db.engine.execute( sql ) + with db.engine.connect() as conn: + conn.exec_driver_sql( sql ) db.session.commit() # reset rating on this series as the book has changed (and maybe the rating has changed) for field in request.form: @@ -705,11 +726,12 @@ def book(id): def GetCount( what, where ): st="select count(id) as count from book where " - res=db.engine.execute( st + where ) + with db.engine.connect() as conn: + res = conn.exec_driver_sql( st+where ) rtn={} for row in res: rtn['stat']=what - rtn['value']=row['count'] + rtn['value']=row.count return rtn @app.route("/stats", methods=["GET"]) @@ -737,7 +759,8 @@ def rem_books_from_loan(id): for field in request.form: rem_id=int(re.findall( '\d+', field )[0]) try: - db.engine.execute("delete from book_loan_link where book_id = {} and loan_id = {}".format( rem_id, id )) + with db.engine.connect() as conn: + conn.exec_driver_sql( "delete from book_loan_link where book_id = {} and loan_id = {}".format( rem_id, id )) db.session.commit() except SQLAlchemyError as e: st.SetAlert("danger") @@ -750,7 +773,8 @@ def add_books_to_loan(id): for field in request.form: add_id=int(re.findall( '\d+', field )[0]) try: - db.engine.execute("insert into book_loan_link (book_id, loan_id) values ( {}, {} )".format( add_id, id )) + with db.engine.connect() as conn: + conn.exec_driver_sql( "insert into book_loan_link (book_id, loan_id) values ( {}, {} )".format( add_id, id )) db.session.commit() except SQLAlchemyError as e: st.SetAlert("danger") @@ -762,8 +786,9 @@ def add_books_to_loan(id): def rem_parent_books_from_series(pid): print ("pid={}".format(pid) ) try: - db.engine.execute("delete from book_series_link where book_id in ( select sub_book_id from book_sub_book_link where book_id = {} ) ".format( pid )) - db.engine.execute("delete from book_series_link where book_id = {}".format( pid )) + with db.engine.connect() as conn: + conn.exec_driver_sql( "delete from book_series_link where book_id in ( select sub_book_id from book_sub_book_link where book_id = {} ) ".format( pid )) + conn.exec_driver_sql( "delete from book_series_link where book_id = {}".format( pid )) db.session.commit() except SQLAlchemyError as e: st.SetAlert("danger") @@ -825,7 +850,8 @@ def unrated_books(): return render_template("books.html", books=books, page_title="Books with no rating", show_cols='Rating', hide_cols='' ) def FindMissingBooks(): - tmp = db.engine.execute("select s.*, count(bsl.book_num) from book_series_link bsl, series s where bsl.book_num is not null and s.id = bsl.series_id group by s.id order by s.title") + with db.engine.connect() as conn: + tmp=conn.exec_driver_sql( "select s.*, count(bsl.book_num) from book_series_link bsl, series s where bsl.book_num is not null and s.id = bsl.series_id group by s.id order by s.title") books=[] sold=Owned.query.filter(Owned.name=='Sold').all() for t in tmp: diff --git a/series.py b/series.py index 1706f76..974de43 100644 --- a/series.py +++ b/series.py @@ -41,13 +41,15 @@ class SeriesForm(FlaskForm): delete = SubmitField('Delete' ) def CalcAvgRating(sid): - res=db.engine.execute( f"select round(avg(to_number(r.name, '99')),1) as rating from book b, rating r, series s, book_series_link bsl where s.id={sid} and s.id = bsl.series_id and bsl.book_id = b.id and b.rating = r.id and r.name ~ E'^\\\\d+$'" ) + with db.engine.connect() as conn: + res=conn.exec_driver_sql( f"select round(avg(to_number(r.name, '99')),1) as rating from book b, rating r, series s, book_series_link bsl where s.id={sid} and s.id = bsl.series_id and bsl.book_id = b.id and b.rating = r.id and r.name ~ E'^\\\\d+$'" ) for row in res: rating = row.rating return rating def ListOfSeriesWithMissingBooks(): - res=db.engine.execute("select id, title, num_books, count from ( select s.id, s.title, s.num_books, count(bsl.book_id) from series s, book_series_link bsl where s.id = bsl.series_id group by s.id ) as foo where num_books > count") + with db.engine.connect() as conn: + res=conn.exec_driver_sql( "select id, title, num_books, count from ( select s.id, s.title, s.num_books, count(bsl.book_id) from series s, book_series_link bsl where s.id = bsl.series_id group by s.id ) as foo where num_books > count") tmp=[] for row in res: tmp.append({'id': row[0], 'title': row[1]})