From 6cef2e0d9ca559cb283a9851b38d3bb2c2fb1868 Mon Sep 17 00:00:00 2001 From: Damien De Paoli Date: Sat, 1 Jul 2023 14:26:36 +1000 Subject: [PATCH] converted over to bal from author, and fixed up the way sub books / series interact --- BUGs | 25 +++-- TODO | 8 ++ main.py | 237 ++++++++++++++++++++++++++++--------------- templates/book.html | 48 ++++++++- templates/books.html | 4 +- 5 files changed, 230 insertions(+), 92 deletions(-) diff --git a/BUGs b/BUGs index a73fa19..14826e8 100644 --- a/BUGs +++ b/BUGs @@ -1,14 +1,23 @@ -### fix to get this working with bs 5... +#### BUGS (next-33) -#### BUGS (next-30) +BUG-6: author does not have explicit ordering like sub-books... + - author inserts need author_num [DONE] + - books on shelf now works with new code [DONE] + TEST THIS - ITS A BREAKING CHANGE.... check every where I used + book.author -> book.bals[]->author -### DB/back-end -### UI not updating after DB change: BUG-7: if you remove a series from a book, it won't appear in the series drop-down if it is the first 'missing' book in that series -- either reset the list, or show all series always? -### ordering of data in UI: -BUG-6: author,series, etc. do not have explicit ordering like sub-books... sort of irritating / needs code and DB fix - - add/remove authors, and after save they are ordered by author.id, not order of addition (prob. needs book_author_link to have an auth_num) +BUG-30: failed to add a book with 2 x same author (need to catch error + or maybe mess with author list to remove duplicate potentials?) -#### SHOWSTOPPER: + +BUG-31: series does not have 'series_num', so a book in 2 series, means he ordering is not explicit + -- UNSURE this is an issue, as 2 series would normally be 1 inside + a larger one, and numbering implies the inner (smaller number), and + outer has explicity overall ordering of books in both series, so + should be ok? + +BUG-32: for book 1546 (with 2 sub-books, 1 with 2 authors), saving it causes 'series removal' dbox to come up + (no series though) diff --git a/TODO b/TODO index e69de29..06643a1 100644 --- a/TODO +++ b/TODO @@ -0,0 +1,8 @@ +TODO: + + # to get from book.author to book.bal + alter table book_author_link add author_num integer; + update book_author_link set author_num = 0; + browse to /fix_an + + * book.parent is an array, not a dict - should change it over diff --git a/main.py b/main.py index df3a774..a6b19e7 100644 --- a/main.py +++ b/main.py @@ -79,16 +79,22 @@ class QuickParentBook: return "".format(self.parent, self.publisher, self.owned, self.covertype, self.condition, self.blurb ) -book_author_link = db.Table('book_author_link', db.Model.metadata, - db.Column('book_id', db.Integer, db.ForeignKey('book.id')), - db.Column('author_id', db.Integer, db.ForeignKey('author.id')) -) - book_genre_link = db.Table('book_genre_link', db.Model.metadata, db.Column('book_id', db.Integer, db.ForeignKey('book.id')), db.Column('genre_id', db.Integer, db.ForeignKey('genre.id')) ) +class Book_Author_Link(db.Model): + __tablename__ = "book_author_link" + book_id = db.Column( db.Integer, db.ForeignKey('book.id'), primary_key=True) + author_id = db.Column( db.Integer, db.ForeignKey('author.id'), primary_key=True) + author_num = db.Column( db.Integer, primary_key=True) + author = db.relationship('Author' ) + + def __repr__(self): + return f"" + + class Book_Loan_Link(db.Model): __tablename__ = "book_loan_link" book_id = db.Column(db.Integer, db.ForeignKey('book.id'), unique=True, nullable=False, primary_key=True) @@ -126,7 +132,6 @@ class Book_Sub_Book_Link(db.Model): class Book(db.Model): id = db.Column(db.Integer, db.Sequence('book_id_seq'), primary_key=True ) title = db.Column(db.String(100), unique=True, nullable=False) - author = db.relationship('Author', secondary=book_author_link) publisher = db.Column(db.Integer, db.ForeignKey('publisher.id')) genre = db.relationship('Genre', secondary=book_genre_link ) loan = db.relationship('Loan', secondary=Book_Loan_Link.__table__); @@ -147,6 +152,8 @@ class Book(db.Model): # but use child_ref as sub_book_num is per book, and I can't connect an empty array of sub_book_nums to a child book array in "child" child_ref = db.relationship('Book_Sub_Book_Link', secondary=Book_Sub_Book_Link.__table__, primaryjoin="Book.id==Book_Sub_Book_Link.book_id", secondaryjoin="Book.id==Book_Sub_Book_Link.sub_book_id", order_by="Book_Sub_Book_Link.sub_book_num", overlaps="parent" ) + # use this to manage author now that author_num is used to order them + bals = db.relationship('Book_Author_Link', order_by="Book_Author_Link.author_num" ) def IsParent(self): if len(self.child_ref): @@ -201,7 +208,7 @@ class Book(db.Model): return redirect( '/series/{}'.format(series_id) ) def __repr__(self): - return "".format(self.id, self.author, self.title, self.year_published, self.rating, self.condition, self.owned, self.covertype, self.notes, self.blurb, self.created, self.modified, self.publisher, self.genre, self.parent ) + return "".format(self.id, self.title, self.year_published, self.rating, self.condition, self.owned, self.covertype, self.notes, self.blurb, self.created, self.modified, self.publisher, self.genre, self.parent ) class Book_Sub_Book_LinkSchema(ma.SQLAlchemyAutoSchema): class Meta: model = Book_Sub_Book_Link @@ -209,11 +216,16 @@ class Book_Sub_Book_LinkSchema(ma.SQLAlchemyAutoSchema): class Book_Series_LinkSchema(ma.SQLAlchemyAutoSchema): class Meta: model = Book_Series_Link +class Book_Author_LinkSchema(ma.SQLAlchemyAutoSchema): + class Meta: model = Book_Author_Link + author = ma.Nested(AuthorSchema ) + # Note not ordering this in the code below as, I can't work out how to use # jinja2 to iterate over orderedDict - seems it doesnt support it? # so I just hacked a list of keys in book.html class BookSchema(ma.SQLAlchemyAutoSchema): author = ma.Nested(AuthorSchema, many=True) + bals = ma.Nested(Book_Author_LinkSchema, many=True) genre = ma.Nested(GenreSchema, many=True) loan = ma.Nested(LoanSchema, many=True) series = ma.Nested(SeriesSchema, many=True) @@ -239,7 +251,6 @@ class BookForm(FlaskForm): rem_sub = SubmitField('Remove Sub-Book from Parent' ) def validate(self): - print( f"type: self.errors={type(self.errors)}" ) # if on wish list, just accept year_published if int(self.owned.data) == ON_WISHLIST: return True @@ -489,20 +500,28 @@ def subbooks_for_book(id): # force sub books for jinja2 to be able to use (ORM is not giving all the details #################################### 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, \ + subs = conn.exec_driver_sql( f"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 \ + author.surname||', '||author.firstnames as author \ from book_sub_book_link bsb, book, book_author_link bal, author, rating r\ - where bsb.book_id = {} and book.id = bsb.sub_book_id and book.id = bal.book_id and \ + where bsb.book_id = {id} and book.id = bsb.sub_book_id and book.id = bal.book_id and \ bal.author_id = author.id and r.id = book.rating \ - order by bsb.sub_book_num".format( id ) ) + order by bsb.sub_book_num, bal.author_num" ) sub_book=[] + added=[] for row in subs: - sub_book.append( { 'book_id': row.book_id, 'sub_book_id': row.sub_book_id, \ - 'sub_book_num': row.sub_book_num, 'title' : row.title, 'rating': row.rating,\ - 'year_published' : row.year_published, 'notes' : row.notes, 'author_id' : row.author_id, 'author' : row.author } ) + if row.sub_book_num not in added: + sub_book.append( { 'book_id': row.book_id, 'sub_book_id': row.sub_book_id, \ + 'sub_book_num': row.sub_book_num, 'title' : row.title, 'rating': row.rating,\ + 'year_published' : row.year_published, 'notes' : row.notes, 'author' : row.author } ) + else: + # okay, same sub_book_num, so its a second author for this sub_book add name to author + for s in sub_book: + if s['sub_book_num'] == row.sub_book_num: + s['author'] += ", " + row.author + added.append(row.sub_book_num) - return render_template("subbooks_for_book.html", sub_books=sub_book, s2=subs ) + return render_template("subbooks_for_book.html", sub_books=sub_book ) ################################################################################ # /remove_subbook -> POST -> removes this subbook from parent, takes you back to @@ -525,6 +544,7 @@ def remove_sub_book(): sb.sub_book_num=sb.sub_book_num-1 # now remove subbook itself + ClearAuthorsForBook(sub_book.id) db.session.delete(sub_book) db.session.commit() return redirect( '/book/{}'.format(request.form['rem_sub_parent_id']) ) @@ -549,18 +569,26 @@ def new_book(): page_title='Create new Book' author_list = GetAuthors() genre_list = GetGenres() - book_authors=[] - for el in request.form: - if 'author-' in el: - book_authors.append( Author.query.get( request.form[el] ) ) book_genres = [] - for genre in genre_list: - if "genre-{}".format(genre.id) in request.form: - book_genres.append( genre ) + + bals=[] + auth_cnt=1 + if request.method == 'POST': + # handle author info for new book + for el in request.form: + if 'author-' in el: + bals.append( Book_Author_Link( author_id=request.form[el], author_num=auth_cnt ) ) + auth_cnt+=1 + + # handle genre info for new book + for genre in genre_list: + if "genre-{}".format(genre.id) in request.form: + book_genres.append( genre ) + + # handle creating a new sub-book of an existing book (add_sub_parent_id) - html / with form data for the new book... if 'add_sub' in request.form: - parent=request.form['add_sub_parent_id'] - book = Book.query.get(parent) + book=Book.query.get(request.form['add_sub_parent_id']) bb=QuickParentBook() bb.parent=[] bb.parent.append( { 'id': parent, 'title': book.title } ) @@ -573,20 +601,24 @@ def new_book(): return render_template("book.html", page_title='Create new (sub) Book', b=bb, books=None, book_form=form, author_list=author_list, genre_list=genre_list, alert="", message="", poss_series_list=ListOfSeriesWithMissingBooks() ) elif form.validate_on_submit() and len(book_genres): if request.form['year_published'].isnumeric(): - book = Book( title=request.form['title'], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], year_published=request.form['year_published'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, author=book_authors ) + book = Book( title=request.form['title'], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], year_published=request.form['year_published'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, bals=bals ) else: - book = Book( title=request.form['title'], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, author=book_authors ) + book = Book( title=request.form['title'], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, bals=bals ) db.session.add(book) db.session.commit() - # this is a sub-book we have added + for tmp_bal in bals: + tmp_bal.book_id=book.id + books.bals=bals + db.session.commit() + + # this is a sub-book we have added (after the data has been entered, now we commit it to DB) if 'parent_id' in request.form: 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 + # 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: 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 ) ) @@ -607,12 +639,15 @@ def new_book(): for field in form.errors: message = "{}
{}={}".format( message, field, form.errors[field] ) if len(book_genres) == 0: - message = "{}
genre=book has to have a genre selected".format( message ) + message = "{}
book has to have a genre selected".format( message ) + if request.form['owned'] != ON_WISHLIST and not request.form['year_published'].isnumeric(): + message = "{}
book is not on wish list, so needs a year_published between 1850 & 2100".format( message ) + print( "ERROR: Failed to create book: {}".format(message) ) if request.form['year_published'].isnumeric(): - book = Book( title=request.form["title"], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], year_published=request.form['year_published'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, author=book_authors ) + book = Book( title=request.form["title"], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], year_published=request.form['year_published'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, bals=bals ) else: - book = Book( title=request.form["title"], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, author=book_authors ) + book = Book( title=request.form["title"], owned=request.form['owned'], covertype=request.form['covertype'], condition=request.form['condition'], publisher=request.form['publisher'], rating=request.form['rating'], notes=request.form['notes'], blurb=request.form['blurb'], genre=book_genres, bals=bals ) if 'parent_id' in request.form: bb=QuickParentBook() @@ -625,6 +660,45 @@ def new_book(): return render_template("book.html", page_title=page_title, b=None, books=None, book_form=form, author_list=author_list, genre_list=genre_list, alert="success", message="", poss_series_list=ListOfSeriesWithMissingBooks() ) +def ClearAuthorsForBook(id): + with db.engine.connect() as conn: + res = conn.exec_driver_sql( f"delete from book_author_link where book_id = {id}" ) + db.session.commit() + +# helper function to reduce code size for /book// route - handles deleting book +def DeleteBook(id): + book = Book.query.get(id) + if book.IsParent(): + st.SetAlert( "danger" ) + st.SetMessage( "This is a parent book, cannot delete it without deleting sub books first" ) + return id + else: + st.SetAlert("success") + st.SetMessage("Deleted {}".format(book.title) ) + pid = 0 + if book.IsChild(): + pid = book.parent[0].id + try: + ClearAuthorsForBook(book.id) + db.session.delete(book) + db.session.commit() + except SQLAlchemyError as e: + st.SetAlert( "danger" ) + st.SetMessage( e.orig ) + return id + except Exception as e: + st.SetAlert( "danger" ) + if "Dependency rule tried to blank-out primary key": + st.SetMessage( f"Failed to delete book: The book has a link to an another table (ddp messed up DB integrity) -- { str(e) }" ) + else: + st.SetMessage( f"Failed to delete book:nbsp; {str(e)} ") + return id + if pid > 0: + return pid + else: + return None + +# handle book view / update / delete route @app.route("/book/", methods=["GET", "POST"]) @login_required def book(id): @@ -638,36 +712,13 @@ def book(id): CheckSeriesChange=None if request.method == 'POST': if 'delete' in request.form: - book = Book.query.get(id) - if book.IsParent(): - st.SetAlert( "danger" ) - st.SetMessage( "This is a parent book, cannot delete it without deleting sub books first" ) - return redirect( '/book/{}'.format(book.id) ) + redirect_to=DeleteBook(id) + if redirect_to == None: + # happens in error conditions only + return redirect( '/' ) else: - st.SetAlert("success") - st.SetMessage("Deleted {}".format(book.title) ) - pid = 0 - if book.IsChild(): - pid = book.parent[0].id - try: - db.session.delete(book) - db.session.commit() - except SQLAlchemyError as e: - st.SetAlert( "danger" ) - st.SetMessage( e.orig ) - return redirect( '/book/{}'.format(id) ) - except Exception as e: - st.SetAlert( "danger" ) - print("generic error") - if 'Dependency rule tried to blank-out primary key': - st.SetMessage( "Failed to delete book: The book has a link to an another table (probably a series) -- {} ".format( str(e) ) ) - else: - st.SetMessage( "Failed to delete book:nbsp; {} ".format( str(e) ) ) - return redirect( '/book/{}'.format(id) ) - if pid > 0: - return redirect( '/book/{}'.format(pid) ) - else: - return redirect( '/' ) + # could return to parent book, or current book depending on what was delted + return redirect( f"/book/{redirect_to}" ) # save/update of book elif book_form.validate(): book = Book.query.get(id) @@ -687,23 +738,23 @@ def book(id): for genre in genre_list: if "genre-{}".format(genre.id) in request.form: book.genre.append( genre ) - # set book author (empty list, in form they are in author-0, author-1, ... author-n) - # so use find them all and append them back to now empty list - book.author=[] + # set book author (empty list) - cant use ORM, not sure why + ClearAuthorsForBook( book.id ) + # then use form data -> author-0, author-1, ... author-n) & append them back to now empty list + cnt=1 for el in request.form: if 'author-' in el: - book.author.append( Author.query.get( request.form[el] ) ) + book.bals.append( Book_Author_Link( author_id=request.form[el], book_id=id, author_num=cnt ) ) + cnt += 1 + # go through form, if we have removed a series, then copy data out of form to be passed into html for a pop-up removing_series=[] for field in request.form: if 'removed-book_num' in field: cnt=int(re.findall( '\d+', field )[0]) removing_series.append( { 'series_id' : request.form['removed-series_id-{}'.format(cnt)] } ) - still_in_series=0 + if book.IsParent(): - for field in request.form: - if 'bsl-book_num-' in field and field != 'bsl-book_num-NUM' and request.form[field] == 'PARENT': - still_in_series=1 # go through children, and force sync any changes of physical parts of parent book tmp_book=book_schema.dump(book) for ch_ref in tmp_book['child_ref']: @@ -715,14 +766,17 @@ def book(id): child_book.condition=book.condition child_book.blurb=book.blurb - # if removing_series has something in it, then handle it - if book.IsChild() or (book.IsParent() and not still_in_series): - if book.IsParent(): - CheckSeriesChange={'type':'parent', 'pid': book.id, 'bid': book.id, 'removing_series': removing_series } - else: - CheckSeriesChange={'type':'child', 'pid': book.parent[0].id, 'bid': book.id, 'removing_series': removing_series } + # okay, saving a parent book and we ARE removing a series, then + # need to pop-up for user, to ask what they want to do with sub-books + # and the series (likely remove them all too, but maybe just the parent?) + if book.IsParent() and len(removing_series) > 0: + CheckSeriesChange={'type':'parent', 'pid': book.id, 'bid': book.id, 'removing_series': removing_series } + # saving a child / sub_book, consider series + if book.IsChild() and len(removing_series) > 0: + CheckSeriesChange={'type':'child', 'pid': book.parent[0].id, 'bid': book.id, 'removing_series': removing_series } else: - # delete all bsls + # either we are a normal book (no parent/child), OR not removing a series, might be adding though, so easiest is to + # delete all bsls and then add them back based on the request.form Book_Series_Link.query.filter(Book_Series_Link.book_id == book.id ).delete() cnt=1 @@ -736,9 +790,14 @@ def book(id): newbsl=Book_Series_Link( book_id=request.form[f'bsl-book_id-{cnt}'], series_id=request.form[f'bsl-series_id-{cnt}'], book_num=request.form[f'bsl-book_num-{cnt}'] ) + # add the contains (null for book_num) bsl for the parent book + if book.IsChild(): + parent_bsl=Book_Series_Link( book_id=book.parent[0].id, series_id=request.form[f'bsl-series_id-{cnt}'] ) + db.session.add(parent_bsl) db.session.add(newbsl) db.session.commit() - # reset rating on this series as the book has changed (and maybe the rating has changed) + + # reset rating on this/these series as the book has changed (and maybe the rating has changed) for field in request.form: if 'bsl-book_id-' in field and field != 'bsl-book_id-NUM': cnt=int(re.findall( '\d+', field )[0]) @@ -849,7 +908,8 @@ def books_on_shelf(): # author, title & the moment we hit a series, the rest of those books are ordered by series # start with all books owned by title, but it includes sub-books, so remove them... - books = Book.query.join(Owned).filter(Owned.name=='Currently Owned').order_by(Book.title).all() +# books = Book.query.join(Owned).filter(Owned.name=='Currently Owned').order_by(Book.title).all() + books = Book.query.join(Owned,Book_Author_Link,Author).filter(Owned.name=='Currently Owned',Book_Author_Link.author_num==1).order_by(Author.surname,Author.firstnames,Book.title).all() RemSubs(books) # because a book can be in multiple series, without any ordering we need to find @@ -890,7 +950,8 @@ def books_on_shelf(): # book not in a series or a sub-book, so just add this book to the ordered list ordered_books.append(b) - return render_template("books.html", books=ordered_books, page_title="Books on Shelf", order_by="Author(s)", show_cols='', hide_cols='' ) +# return render_template("books.html", books=ordered_books, page_title="Books on Shelf", order_by="Author(s)", show_cols='', hide_cols='' ) + return render_template("books.html", books=ordered_books, page_title="Books on Shelf", order_by="", show_cols='', hide_cols='' ) @app.route("/unrated_books", methods=["GET"]) @login_required @@ -962,10 +1023,26 @@ def poor_rating_books(): return render_template("books.html", books=books, page_title="Books that have a Poor Rating (<5 out of 10)", show_cols='Rating', hide_cols='' ) +@app.route("/fix_an") +@login_required +def fix_an(): + books=Book.query.all(); + for b in books: + cnt=1 + for a in b.author: + bal=Book_Author_Link.query.filter(Book_Author_Link.book_id==b.id,Book_Author_Link.author_id==a.id,Book_Author_Link.author_num == 0 ).first() + bal.author_num=cnt + db.session.add(bal) + cnt+=1 + db.session.commit() + return render_template("base.html", alert="success", message="Fixed author numbering" ) + + # default page, just the navbar @app.route("/", methods=["GET"]) @login_required def main_page(): + # Redirect users who are not logged in. if not current_user or current_user.is_anonymous: return redirect(url_for('login')) diff --git a/templates/book.html b/templates/book.html index 685b144..be06915 100644 --- a/templates/book.html +++ b/templates/book.html @@ -200,7 +200,11 @@ function AddAuthorToBook(num) { } -{% set keys = [ 'title', 'author', 'publisher', 'genre', 'owned', 'covertype', 'condition', 'year_published', 'rating', 'notes', 'blurb' ] %} +{# +{% set keys = [ 'title', 'bals', 'author', 'publisher', 'genre', 'owned', 'covertype', 'condition', 'year_published', 'rating', 'notes', 'blurb' ] %} +#} + +{% set keys = [ 'title', 'bals', 'publisher', 'genre', 'owned', 'covertype', 'condition', 'year_published', 'rating', 'notes', 'blurb' ] %}

{{page_title}}

@@ -223,7 +227,11 @@ function AddAuthorToBook(num) { {% endif %} {% for key in keys %}
- + {% if key == "bals" %} + + {% else %} + + {% endif %} {% if key == "genre" %}
{% for genre in genre_list %} @@ -239,6 +247,42 @@ function AddAuthorToBook(num) {
{% endfor %}
+ {% elif key == "bals" %} + {% set cnt = namespace(idx=1) %} + {% for a in books[key] %} + {% if cnt.idx > 1 %} + + {% endif %} + + {% set cnt.idx = cnt.idx+1 %} + {% endfor %} + {# if idx is still 1, then no authors - new book, just put one there - book HAS to have an author #} + {% if cnt.idx == 1 %} + + {% elif key == "author" %} {% set cnt = namespace(idx=0) %} {% for objects in books[key] %} diff --git a/templates/books.html b/templates/books.html index 811691b..f7cab79 100644 --- a/templates/books.html +++ b/templates/books.html @@ -39,8 +39,8 @@ {{book.title}} {% endif %} - {% for auth in book.author %} - {{ auth['surname'] }}, {{auth['firstnames']}} + {% for auth in book.bals %} + {{ auth.author.surname}}, {{auth.author.firstnames}} {% endfor %} {% if not InDBox %}