first pass for series data, can save, and shows associated books... Does not deal with series inside series

This commit is contained in:
2020-11-23 18:50:53 +11:00
parent 7bd3ff4c26
commit e7c8e645ae
6 changed files with 184 additions and 3 deletions

15
main.py
View File

@@ -23,6 +23,7 @@ from covertype import Covertype, CovertypeForm, CovertypeSchema, GetCovertypeByI
from owned import Owned, OwnedForm, OwnedSchema, GetOwnedById
from rating import Rating, RatingForm, RatingSchema
from loan import Loan, LoanForm, LoanSchema
from series import Series, SeriesForm, SeriesSchema
# allow jinja2 to call this python function
app.jinja_env.globals['GetCovertypeById'] = GetCovertypeById
@@ -50,6 +51,11 @@ class Book_Loan_Link(db.Model):
book_id = db.Column(db.Integer, db.ForeignKey('book.id'), unique=True, nullable=False, primary_key=True)
loan_id = db.Column(db.Integer, db.ForeignKey('loan.id'), unique=True, nullable=False, primary_key=True)
class Book_Series_Link(db.Model):
__tablename__ = "book_series_link"
book_id = db.Column(db.Integer, db.ForeignKey('book.id'), unique=True, nullable=False, primary_key=True)
series_id = db.Column(db.Integer, db.ForeignKey('series.id'), unique=True, nullable=False, primary_key=True)
class Book_Sub_Book_Link(db.Model):
__tablename__ = "book_sub_book_link"
book_id = db.Column(db.Integer, db.ForeignKey('book.id'), unique=True, nullable=False, primary_key=True)
@@ -66,6 +72,7 @@ class Book(db.Model):
publisher = db.relationship('Publisher', secondary=book_publisher_link)
genre = db.relationship('Genre', secondary=book_genre_link )
loan = db.relationship('Loan', secondary=Book_Loan_Link.__table__);
series = db.relationship('Series', secondary=Book_Series_Link.__table__);
year_published = db.Column(db.Integer)
condition = db.Column(db.Integer, db.ForeignKey('condition.id'))
covertype = db.Column(db.Integer, db.ForeignKey('covertype.id'))
@@ -136,12 +143,14 @@ def books():
@app.route("/books_for_loan/<id>", methods=["GET"])
def books_for_loan(id):
# books = db.engine.execute ( "select * from book_loan_link where loan_id = {}".format( id ) )
print( id )
books = Book.query.join(Book_Loan_Link).filter(Book_Loan_Link.loan_id==id).order_by(Book.id).all()
print( books )
return render_template("books_for_loan.html", books=books)
@app.route("/books_for_series/<id>", methods=["GET"])
def books_for_series(id):
books = Book.query.join(Book_Series_Link).filter(Book_Series_Link.series_id==id).order_by(Book.id).all()
return render_template("books_for_series.html", books=books)
@app.route("/book/<id>", methods=["GET"])
def book(id):
book = Book.query.get(id)

78
series.py Normal file
View File

@@ -0,0 +1,78 @@
from wtforms import SubmitField, StringField, HiddenField, validators, TextAreaField, IntegerField
from flask_wtf import FlaskForm
from flask import request, render_template
from wtforms.fields.html5 import DateField
from __main__ import db, app, ma
################################################################################
# Class describing Series in the database, and via sqlalchemy, connected to the DB as well
################################################################################
class Series(db.Model):
id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True)
title = db.Column(db.String(100), unique=False, nullable=False)
num_books = db.Column(db.Integer, nullable=False)
calcd_rating = db.Column(db.String(10), unique=False, nullable=False)
note = db.Column(db.Text)
def __repr__(self):
return "<id: {}, title: {}, num_books: {}, calcd_rating: {}, note: {}>".format(self.id, self.title, self.num_books, self.calcd_rating, self.note)
################################################################################
# Helper class that inherits a .dump() method to turn class Series into json / useful in jinja2
################################################################################
class SeriesSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Series
ordered = True
################################################################################
# Helper class that defines a form for series, used to make html <form>, with field validation (via wtforms)
################################################################################
class SeriesForm(FlaskForm):
id = HiddenField()
title = StringField('Title:', [validators.DataRequired()])
num_books = IntegerField('Number of Books:', [validators.NumberRange(min=1)])
calcd_rating = StringField('Avg Rating:' )
note = TextAreaField('Notes:')
submit = SubmitField('Save' )
delete = SubmitField('Delete' )
################################################################################
# Routes for series data
#
# /seriess -> GET only -> prints out list of all seriess
################################################################################
@app.route("/seriess", methods=["GET"])
def seriess():
seriess = Series.query.all()
return render_template("seriess.html", seriess=seriess)
################################################################################
# /series/<id> -> GET/POST(save or delete) -> shows/edits/delets a single
# series
################################################################################
@app.route("/series/<id>", methods=["GET", "POST"])
def series(id):
### DDP: should this be request.form or request.values?
alert="Success"
series_form = SeriesForm(request.form)
if request.method == 'POST' and series_form.validate_on_submit():
id = request.form['id']
series = Series.query.get(id)
try:
request.form['submit']
except:
message="Sorry, Deleting unsupported at present"
alert="Danger"
else:
series.title = request.form['title']
series.num_books = request.form['num_books']
# series.calcd_rating =
series.note = request.form['note']
db.session.commit()
message="Successfully Updated Series (id={})".format(id)
else:
series = Series.query.get(id)
series_form = SeriesForm(request.values, obj=series)
message=""
return render_template("series.html", series=series, alert=alert, message=message, series_form=series_form)

View File

@@ -42,6 +42,13 @@
<a class="dropdown-item" href="{{url_for('publishers')}}">Show All</a>
</div>
</div>
<div class="nav-item dropdown">
<a class="nav-item dropdown nav-link dropdown-toggle" href="#" id="SeriesMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Series</a>
<div class="dropdown-menu" aria-labelledby="SeriesMenu">
<a class="dropdown-item" href="{{url_for('seriess')}}">Create</a>
<a class="dropdown-item" href="{{url_for('seriess')}}">Show All</a>
</div>
</div>
<div class="nav-item dropdown">
<a class="nav-item dropdown nav-link dropdown-toggle" href="#" id="AdminMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Admin</a>
<div class="dropdown-menu" aria-labelledby="AdminMenu">

View File

@@ -0,0 +1,18 @@
<h3>Books in Series</h1>
<table id="book_table" class="table table-striped table-sm" data-toolbar="#toolbar" data-search="true">
<thead>
<tr class="thead-light"><th>Title</th><th>Book Number</th></tr>
</thead>
<tbody>
{% for book in books %}
<tr>
{% if book.sub_book_num is defined %}
<td data-sort="{{book.parent_id}}.{{book.sub_book_num}}"><a href="/book/{{book.id}}">&nbsp;&nbsp;&nbsp;&nbsp;{{book.title}}</a></td>
{% else %}
<td data-sort="{{book.id}}"><a href="/book/{{book.id}}">{{book.title}}</a></td>
{% endif %}
<td>not yet:</a></td>
</tr>
{% endfor %}
</tbody>
</table>

53
templates/series.html Normal file
View File

@@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block main_content %}
<div class="container">
<h3 class="col-lg-12"><center>Series</center></h3>
{% if message|length %}
<div class="row alert alert-{{alert}}">
{{message}}
</div>
{% endif %}
<div class="row">
<div class="col-lg-8">
<form class="form form-inline col-lg-12" action="" method="POST">
{{ series_form.csrf_token }}
{{ series_form.id }}
<div class="form-row col-lg-12">
{{ series_form.title.label( class="col-lg-3 justify-content-end" ) }}
{{ series_form.title( class="form-control col-lg-9" ) }}
</div class="form-row">
<div class="form-row col-lg-12">
{{ series_form.num_books.label( class="col-lg-3 justify-content-end" ) }}
{{ series_form.num_books( class="form-control col-lg-9" ) }}
</div class="form-row">
<div class="form-row col-lg-12">
{{ series_form.calcd_rating.label( class="col-lg-3 justify-content-end" ) }}
{{ series_form.calcd_rating( class="form-control col-lg-9", readonly="true" ) }}
</div class="form-row">
<div class="form-row col-lg-12">
{{ series_form.note.label( class="col-lg-3 justify-content-end" ) }}
{{ series_form.note( class="form-control col-lg-9", rows="5" ) }}
</div class="form-row">
<div class="row col-lg-12">
<br>
</div class="row">
<div class="form-row col-lg-12">
{{ series_form.delete( class="btn btn-outline-danger col-lg-2 offset-lg-1" )}}
{{ series_form.submit( class="btn btn-primary col-lg-2" )}}
</div class="form-row">
</form>
</div class="col-lg-8">
<div class="col-lg-4">
<div id="books_for_series_bit">
</div id="books_for_series_bit">
</div class="col-lg-4">
</div class="row">
</div class="container">
{% endblock main_content %}
{% block script_content %}
<script>
$(document).ready( function() {
$("#books_for_series_bit").load("/books_for_series/" + {{series_form.data.id}})
} )
</script>
{% endblock script_content %}

16
templates/seriess.html Normal file
View File

@@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block main_content %}
<h3>Series</h3>
<table id="book_table" class="table table-striped table-sm" data-toolbar="#toolbar" data-search="true">
<thead>
<tr class="thead-light"><th>Title</th><th>Number of Books</th><th>Rating (average)</th><th>Notes</th></tr>
</thead>
<tbody>
{% for series in seriess %}
<tr><td><a href="{{url_for('series', id=series.id )}}">{{series.title}}</a></td><td>{{series.num_books}}</td><td>{{series.calcd_rating}}</td>
<td>{{series.note}}</td></tr>
{% endfor %}
</tbody>
</table>
{% endblock main_content %}