From 9544790ffaba706c7bdc22742114b019c3661d6a Mon Sep 17 00:00:00 2001 From: Damien De Paoli Date: Tue, 17 Nov 2020 21:22:15 +1100 Subject: [PATCH] removed all old *_lst tables, added corresponding new classes, etc. fro covertype, owned, rating, and dropped tables from DB, etc. Updated base.html to use new tables as drop-downs that are set correctly. So far slight hack on BookForm, will finish that after syncing this all back to mara. If I do the sync, and export/import this version of DB, then the fixes.sql and fix_db() code included in main.py can be removed. Finally, lamely added a favicon and a static/ to support it --- README | 2 +- condition.py | 2 - covertype.py | 66 +++++++++++++++++++++++++++++++++ fixes.sql | 75 ++++++++++++++++++++++++++++++++++++-- main.py | 42 ++++++++++++++++----- owned.py | 66 +++++++++++++++++++++++++++++++++ rating.py | 66 +++++++++++++++++++++++++++++++++ static/favicon.ico | Bin 0 -> 15086 bytes templates/base.html | 9 ++++- templates/book.html | 68 +++++++++++++++++++--------------- templates/covertype.html | 24 ++++++++++++ templates/covertypes.html | 15 ++++++++ templates/owned.html | 24 ++++++++++++ templates/owneds.html | 15 ++++++++ templates/rating.html | 24 ++++++++++++ templates/ratings.html | 15 ++++++++ 16 files changed, 466 insertions(+), 47 deletions(-) create mode 100644 covertype.py create mode 100644 owned.py create mode 100644 rating.py create mode 100644 static/favicon.ico create mode 100644 templates/covertype.html create mode 100644 templates/covertypes.html create mode 100644 templates/owned.html create mode 100644 templates/owneds.html create mode 100644 templates/rating.html create mode 100644 templates/ratings.html diff --git a/README b/README index 339358f..e0e3253 100644 --- a/README +++ b/README @@ -14,7 +14,7 @@ sudo apt install python3-pip python3-psycopg2 libpq-dev pip3 install --user flask sqlalchemy flask-sqlalchemy flask-marshmallow SQLAlchemy-serializer flask-wtf flask-bootstrap marshmallow-sqlalchemy -### alter db that was saved by: +### fix up db changes by running those in fixes.sql psql library alter table genre_lst rename to genre; alter table genre rename COLUMN genre to name; diff --git a/condition.py b/condition.py index ad1d882..eaac9a6 100644 --- a/condition.py +++ b/condition.py @@ -36,8 +36,6 @@ class ConditionForm(Form): @app.route("/conditions", methods=["GET"]) def conditions(): conditions = Condition.query.order_by('id').all() - print ( Condition.query.order_by('id') ) - print ( conditions ) return render_template("conditions.html", conditions=conditions) ################################################################################ diff --git a/covertype.py b/covertype.py new file mode 100644 index 0000000..871cb8b --- /dev/null +++ b/covertype.py @@ -0,0 +1,66 @@ +from wtforms import SubmitField, StringField, HiddenField, SelectField, validators, Form +from flask import request, render_template +from __main__ import db, app, ma + +################################################################################ +# Class describing Covertype in the database, and via sqlalchemy, connected to the DB as well +################################################################################ +class Covertype(db.Model): + id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True) + name = db.Column(db.String(50), unique=False, nullable=False) + + def __repr__(self): + return "".format(self.id,self.name) + +################################################################################ +# Helper class that inherits a .dump() method to turn class Covertype into json / useful in jinja2 +################################################################################ +class CovertypeSchema(ma.SQLAlchemyAutoSchema): + class Meta: model = Covertype + + +################################################################################ +# Helper class that defines a form for covertype, used to make html
, with field validation (via wtforms) +################################################################################ +class CovertypeForm(Form): + id = HiddenField() + name = StringField('Name:', [validators.DataRequired()]) + submit = SubmitField('Save' ) + delete = SubmitField('Delete' ) + +################################################################################ +# Routes for covertype data +# +# /covertypes -> GET only -> prints out list of all covertypes +################################################################################ +@app.route("/covertypes", methods=["GET"]) +def covertypes(): + covertypes = Covertype.query.order_by('id').all() + return render_template("covertypes.html", covertypes=covertypes) + +################################################################################ +# /covertype/ -> GET/POST(save or delete) -> shows/edits/delets a single +# covertype +################################################################################ +@app.route("/covertype/", methods=["GET", "POST"]) +def covertype(id): + ### DDP: should this be request.form or request.values? + alert="Success" + covertype_form = CovertypeForm(request.form) + if request.method == 'POST' and covertype_form.validate(): + id = request.form['id'] + covertype = Covertype.query.get(id) + try: + request.form['submit'] + except: + message="Sorry, Deleting unsupported at present" + alert="Danger" + else: + covertype.name = request.form['name'] + db.session.commit() + message="Successfully Updated Covertype (id={})".format(id) + else: + covertype = Covertype.query.get(id) + covertype_form = CovertypeForm(request.values, obj=covertype) + message="" + return render_template("covertype.html", covertype=covertype, alert=alert, message=message, covertype_form=covertype_form) diff --git a/fixes.sql b/fixes.sql index 22fa8c0..9d023f0 100644 --- a/fixes.sql +++ b/fixes.sql @@ -1,10 +1,79 @@ +ALTER TABLE genre_lst RENAME TO genre; +ALTER TABLE genre RENAME COLUMN genre TO name; + CREATE TABLE condition ( - id INTEGER, - name VARCHAR(20) not null, - constraint pk_condition primary key(id) + id INTEGER, + name VARCHAR(20) not null, + constraint pk_condition primary key(id) ); INSERT INTO condition VALUES ( 1, 'Good' ); INSERT INTO condition VALUES ( 2, 'Average' ); INSERT INTO condition VALUES ( 3, 'Needs Replacing' ); INSERT INTO condition VALUES ( 4, 'N/A' ); +ALTER TABLE book ADD COLUMN temp_cond integer , ADD CONSTRAINT fk_book_condition_new foreign key(temp_cond) REFERENCES condition(id) +CREATE TABLE covertype ( + id INTEGER, + name VARCHAR(20) not null, + constraint pk_covertype primary key(id) +); +INSERT INTO covertype VALUES ( 1, 'Paperback' ); +INSERT INTO covertype VALUES ( 2, 'Over-size Paperback' ); +INSERT INTO covertype VALUES ( 3, 'Hardcover' ); +INSERT INTO covertype VALUES ( 4, 'N/A' ); +ALTER TABLE book ADD COLUMN temp_cover integer , ADD CONSTRAINT fk_book_covertype_new foreign key(temp_cover) REFERENCES covertype(id) + +CREATE TABLE owned ( + id INTEGER, + name VARCHAR(20) not null, + constraint pk_owned primary key(id) +); +INSERT INTO owned VALUES ( 1, 'Currently Owned' ); +INSERT INTO owned VALUES ( 2, 'On Wish List' ); +INSERT INTO owned VALUES ( 3, 'Sold' ); +ALTER TABLE book ADD COLUMN temp_owned integer , ADD CONSTRAINT fk_book_owned_new foreign key(temp_owned) REFERENCES owned(id); + +CREATE TABLE rating ( + id INTEGER, + name VARCHAR(20) not null, + constraint pk_rating primary key(id) +); +INSERT INTO rating VALUES ( 1, '10' ); +INSERT INTO rating VALUES ( 2, '9' ); +INSERT INTO rating VALUES ( 3, '8' ); +INSERT INTO rating VALUES ( 4, '7' ); +INSERT INTO rating VALUES ( 5, '6' ); +INSERT INTO rating VALUES ( 6, '5' ); +INSERT INTO rating VALUES ( 7, '4' ); +INSERT INTO rating VALUES ( 8, '3' ); +INSERT INTO rating VALUES ( 9, '2' ); +INSERT INTO rating VALUES ( 10, '1' ); +INSERT INTO rating VALUES ( 11, 'N/A' ); +INSERT INTO rating VALUES ( 12, 'Undefined' ); +ALTER TABLE book ADD COLUMN temp_rating integer, ADD CONSTRAINT fk_book_rating_new foreign key(temp_rating) REFERENCES rating(id); + + +### fore each new table (e.g do above), then +# add appropriate new field to Book class definition, eg for condition: +temp_cond = db.Column(db.Integer) + +# then run python code with fix_db() -- which fixes appropriate Book., then: + +ALTER TABLE book DROP COLUMN condition; +ALTER TABLE book RENAME COLUMN temp_cond TO condition; + +ALTER TABLE book DROP COLUMN covertype; +ALTER TABLE book RENAME COLUMN temp_cover TO covertype; + +ALTER TABLE book DROP COLUMN owned; +ALTER TABLE book RENAME COLUMN temp_owned TO owned; + +ALTER TABLE book DROP COLUMN rating; +ALTER TABLE book RENAME COLUMN temp_rating TO rating; + +DROP TABLE condition_lst +DROP TABLE covertype_lst +DROP TABLE owned_lst +DROP TABLE rating_lst + +# then modify main.py again, to delete condition and rename temp_ to in class Book diff --git a/main.py b/main.py index 66fc9df..15ba7d7 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,9 @@ -from flask import Flask -from flask import render_template -from flask import request +from flask import Flask, render_template, request from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from flask_bootstrap import Bootstrap from wtforms import SubmitField, StringField, HiddenField, SelectField, validators, Form +from flask_wtf import FlaskForm app = Flask(__name__) ### what is this value? I gather I should chagne it? @@ -20,6 +19,9 @@ from author import Author, AuthorForm, AuthorSchema from publisher import Publisher, PublisherForm, PublisherSchema from genre import Genre, GenreForm, GenreSchema from condition import Condition, ConditionForm, ConditionSchema +from covertype import Covertype, CovertypeForm, CovertypeSchema +from owned import Owned, OwnedForm, OwnedSchema +from rating import Rating, RatingForm, RatingSchema ####################################### CLASSES / DB model ####################################### book_author_link = db.Table('book_author_link', db.Model.metadata, @@ -53,10 +55,10 @@ class Book(db.Model): publisher = db.relationship('Publisher', secondary=book_publisher_link) genre = db.relationship('Genre', secondary=book_genre_link ) year_published = db.Column(db.Integer) - owned = db.Column(db.String(20)) - covertype = db.Column(db.String(20)) - condition = db.Column(db.String(20)) - rating = db.Column(db.String(20)) + condition = db.Column(db.Integer, db.ForeignKey('condition.id')) + covertype = db.Column(db.Integer, db.ForeignKey('covertype.id')) + owned = db.Column(db.Integer, db.ForeignKey('owned.id')) + rating = db.Column(db.Integer, db.ForeignKey('rating.id')) notes = db.Column(db.Text) blurb = db.Column(db.Text) created = db.Column(db.Date) @@ -85,12 +87,15 @@ class BookSchema(ma.SQLAlchemyAutoSchema): # # To be completed # -class BookForm(Form): +class BookForm(FlaskForm): # I think I'll have to skip setting default on create, and using jquery to # change it when I create the from? (or maybe I could use a default=set_me # in the line below, then when I set create set_me = book.condition before # bf=BookForm() condition = SelectField( 'condition', choices=[(c.id, c.name) for c in Condition.query.order_by('id')] ) + covertype = SelectField( 'covertype', choices=[(c.id, c.name) for c in Covertype.query.order_by('id')] ) + owned = SelectField( 'owned', choices=[(c.id, c.name) for c in Owned.query.order_by('id')] ) + rating = SelectField( 'rating', choices=[(c.id, c.name) for c in Rating.query.order_by('id')] ) ### DDP: do I need many=True on Author as books have many authors? (or in BookSchema declaration above?) @@ -136,11 +141,30 @@ def book(id): book_s['sub_book'] = sub_book - return render_template("book.html", books=book_s, subs=sub_book ) + book_form=BookForm(request.form) + # set defaults for drop-down's based on this book + book_form.condition.default = book.condition + book_form.covertype.default = book.covertype + book_form.owned.default = book.owned + book_form.rating.default = book.rating + print(book_form) + book_form.process() + return render_template("book.html", books=book_s, subs=sub_book, book_form=book_form ) @app.route("/", methods=["GET"]) def main_page(): return render_template("base.html") +def fix_db(): + books = Book.query.all() + for book in books: + rating=Rating.query.filter_by(name=book.rating).all() + book.temp_rating=rating[0].id + print(book.temp_rating) + db.session.commit() + print( "ran fix_db()") + + if __name__ == "__main__": +# fix_db() app.run(host="0.0.0.0", debug=True) diff --git a/owned.py b/owned.py new file mode 100644 index 0000000..870080d --- /dev/null +++ b/owned.py @@ -0,0 +1,66 @@ +from wtforms import SubmitField, StringField, HiddenField, SelectField, validators, Form +from flask import request, render_template +from __main__ import db, app, ma + +################################################################################ +# Class describing Owned in the database, and via sqlalchemy, connected to the DB as well +################################################################################ +class Owned(db.Model): + id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True) + name = db.Column(db.String(50), unique=False, nullable=False) + + def __repr__(self): + return "".format(self.id,self.name) + +################################################################################ +# Helper class that inherits a .dump() method to turn class Owned into json / useful in jinja2 +################################################################################ +class OwnedSchema(ma.SQLAlchemyAutoSchema): + class Meta: model = Owned + + +################################################################################ +# Helper class that defines a form for owned, used to make html , with field validation (via wtforms) +################################################################################ +class OwnedForm(Form): + id = HiddenField() + name = StringField('Name:', [validators.DataRequired()]) + submit = SubmitField('Save' ) + delete = SubmitField('Delete' ) + +################################################################################ +# Routes for owned data +# +# /owneds -> GET only -> prints out list of all owneds +################################################################################ +@app.route("/owneds", methods=["GET"]) +def owneds(): + owneds = Owned.query.order_by('id').all() + return render_template("owneds.html", owneds=owneds) + +################################################################################ +# /owned/ -> GET/POST(save or delete) -> shows/edits/delets a single +# owned +################################################################################ +@app.route("/owned/", methods=["GET", "POST"]) +def owned(id): + ### DDP: should this be request.form or request.values? + alert="Success" + owned_form = OwnedForm(request.form) + if request.method == 'POST' and owned_form.validate(): + id = request.form['id'] + owned = Owned.query.get(id) + try: + request.form['submit'] + except: + message="Sorry, Deleting unsupported at present" + alert="Danger" + else: + owned.name = request.form['name'] + db.session.commit() + message="Successfully Updated Owned (id={})".format(id) + else: + owned = Owned.query.get(id) + owned_form = OwnedForm(request.values, obj=owned) + message="" + return render_template("owned.html", owned=owned, alert=alert, message=message, owned_form=owned_form) diff --git a/rating.py b/rating.py new file mode 100644 index 0000000..4170197 --- /dev/null +++ b/rating.py @@ -0,0 +1,66 @@ +from wtforms import SubmitField, StringField, HiddenField, SelectField, validators, Form +from flask import request, render_template +from __main__ import db, app, ma + +################################################################################ +# Class describing Rating in the database, and via sqlalchemy, connected to the DB as well +################################################################################ +class Rating(db.Model): + id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True) + name = db.Column(db.String(50), unique=False, nullable=False) + + def __repr__(self): + return "".format(self.id,self.name) + +################################################################################ +# Helper class that inherits a .dump() method to turn class Rating into json / useful in jinja2 +################################################################################ +class RatingSchema(ma.SQLAlchemyAutoSchema): + class Meta: model = Rating + + +################################################################################ +# Helper class that defines a form for rating, used to make html , with field validation (via wtforms) +################################################################################ +class RatingForm(Form): + id = HiddenField() + name = StringField('Name:', [validators.DataRequired()]) + submit = SubmitField('Save' ) + delete = SubmitField('Delete' ) + +################################################################################ +# Routes for rating data +# +# /ratings -> GET only -> prints out list of all ratings +################################################################################ +@app.route("/ratings", methods=["GET"]) +def ratings(): + ratings = Rating.query.order_by('id').all() + return render_template("ratings.html", ratings=ratings) + +################################################################################ +# /rating/ -> GET/POST(save or delete) -> shows/edits/delets a single +# rating +################################################################################ +@app.route("/rating/", methods=["GET", "POST"]) +def rating(id): + ### DDP: should this be request.form or request.values? + alert="Success" + rating_form = RatingForm(request.form) + if request.method == 'POST' and rating_form.validate(): + id = request.form['id'] + rating = Rating.query.get(id) + try: + request.form['submit'] + except: + message="Sorry, Deleting unsupported at present" + alert="Danger" + else: + rating.name = request.form['name'] + db.session.commit() + message="Successfully Updated Rating (id={})".format(id) + else: + rating = Rating.query.get(id) + rating_form = RatingForm(request.values, obj=rating) + message="" + return render_template("rating.html", rating=rating, alert=alert, message=message, rating_form=rating_form) diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..36e63975fb3aa57cbccd5d3776cc9f21ed974c03 GIT binary patch literal 15086 zcmeI3OK4nG7=X`oY*MX{DhRfr&Cn=Rq)=THMWI^6g$rHyS``ANw73yLtq*DjDlQc1 z!WKbS;&bCdH$}0~A`0rltx#;^LKiO7s?e!vbN#-Vd&BAVW_mLw?L^MNm-G5x=g+w} z_x?;mXoP0ivL(>A!iP77ur-9xYUSfKA)H`t4Xx{YE(_sh1U4aqN|*%ayPq3-P5PNK zkTQ@mkTNiw8JN61TLsM`I{GW&@?t!UE%B{@^{@v%g}vaMyZ}eQHDy)|!ybskyl#L8 z;2?YtXCZ^H;i??_&bg+Hvg)Y2a;f)%k0x9RV{j`x1XJ)a`~YXb_+q|ge07ffc+I{# z>S|*Ow5e@<=xgr$Eo6V_O~52P1uwxH@DY3o$Kh9)fpR?M@rB|q%WG5H`p}m?^=%Bs zVoVeL_QLu`_y)?h2N^Fk{yIL4ZR31g6fjf2#A8&QEn-(*37iUefugm#1|9 zsm@b6Kh=5pKiz+hyP&?G|HfZHH5RY@TE74>$pz!)x#`ShuTP zhgCM$d4yIQ+R~=B^)cT*jBR@nZ@Fb{1RjSk;43%`@4*3h8qDtvc3jBTVGcRXgj0jt3pu=}}WwR(N$F&K+6HR4!PKV=|gAY~wBVDJoN-A@RE zw=*ZRO#Nf~yX|bFJ;iu7G}>V*gx_tiS=%FA>a>Gi|Ni~{8Qun;Bbqt(opY_u^Fx*Yedxxq z&ocJ8>KFJ9-T|LsZiau=WSz^`lu=e4b+w_b*!I5Cs4xWcsU@uIOIAUD6>T z{C_gb5-pgkQ}DlL%i+Uy>~%f?n{w>Wd!Jy + {% import "bootstrap/wtf.html" as wtf %} @@ -48,8 +49,12 @@ Show Genres Create new Condition Show Conditions - Create new Covertype - Show Covertypes + Create new Covertype + Show Covertypes + Create new Owned Type + Show Owned Types + Create new Rating + Show Owned Ratings diff --git a/templates/book.html b/templates/book.html index 51d4660..4f4c25a 100644 --- a/templates/book.html +++ b/templates/book.html @@ -3,44 +3,52 @@

View/Edit Book

{% set keys = [ 'title', 'author', 'publisher', 'genre', 'owned', 'covertype', 'condition', 'year_published', 'rating', 'notes', 'blurb' ] %}
-
+
{% for key in keys %} -
+{% if key == "condition" or key == "covertype" or key == "owned" or key == "rating" %} +
+ +
+ {{book_form[key](class="form-control")}} +
+
+{% else %} +
-
- {% if books[key] is iterable and books[key] is not string %} - {% set cnt = namespace(idx=0, val=0) %} - {% for objects in books[key] %} - {% set cnt.val = 0 %} - {% set str = namespace(val="") %} - {% for attr in objects %} - {% if attr != "id" %} - {% if cnt.val > 0 %} - {% set str.val=str.val+", "+objects[attr] %} - {% else %} - {% set str.val=str.val+objects[attr] %} + {% if books[key] is iterable and books[key] is not string %} +
+ {% set cnt = namespace(idx=0, val=0) %} + {% for objects in books[key] %} + {% set cnt.val = 0 %} + {% set str = namespace(val="") %} + {% for attr in objects %} + {% if attr != "id" %} + {% if cnt.val > 0 %} + {% set str.val=str.val+", "+objects[attr] %} + {% else %} + {% set str.val=str.val+objects[attr] %} + {% endif %} + {% set cnt.val = cnt.val + 1 %} {% endif %} - {% set cnt.val = cnt.val + 1 %} - {% endif %} + {% endfor %} + + {{str.val}} + + {% set cnt.idx = cnt.idx+1 %} {% endfor %} - - {{str.val}} - - {% set cnt.idx = cnt.idx+1 %} - {% endfor %} -
- - {% else %} - {% if key == "notes" or key == "blurb" %} - +
{% else %} - + {% if key == "notes" or key == "blurb" %} + + {% else %} + + {% endif %} {% endif %} - {% endif %} -
-
+
+
+{% endif %} {% endfor %}
diff --git a/templates/covertype.html b/templates/covertype.html new file mode 100644 index 0000000..16e0b8d --- /dev/null +++ b/templates/covertype.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} {% block main_content %} +

Covertype

+
+ + {% if message|length %} +
+ {{message}} +
+ {% endif %} +
+
+ {{ wtf.form_field( covertype_form.id, form_type='inline' ) }} +
+ {{ wtf.form_field( covertype_form.name, form_type='horizontal', horizontal_columns=('xl', 2, 10), style="width:100%" ) }} +
+
+

+
+ {{ wtf.form_field( covertype_form.submit, horizontal_columns=('xl', 2, 2), class="btn btn-primary offset-xl-1 col-xl-2" )}} + {{ wtf.form_field( covertype_form.delete, horizontal_columns=('xl', 2, 2), class="btn btn-danger offset-xl-1 col-xl-2" )}} +
+
+
+{% endblock main_content %} diff --git a/templates/covertypes.html b/templates/covertypes.html new file mode 100644 index 0000000..527287f --- /dev/null +++ b/templates/covertypes.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block main_content %} +

Covertypes

+ + + + + + {% for covertype in covertypes %} + + {% endfor %} + +
Name
{{covertype.name}}
+{% endblock main_content %} diff --git a/templates/owned.html b/templates/owned.html new file mode 100644 index 0000000..86f0544 --- /dev/null +++ b/templates/owned.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} {% block main_content %} +

Owned

+
+ + {% if message|length %} +
+ {{message}} +
+ {% endif %} +
+
+ {{ wtf.form_field( owned_form.id, form_type='inline' ) }} +
+ {{ wtf.form_field( owned_form.name, form_type='horizontal', horizontal_columns=('xl', 2, 10), style="width:100%" ) }} +
+
+

+
+ {{ wtf.form_field( owned_form.submit, horizontal_columns=('xl', 2, 2), class="btn btn-primary offset-xl-1 col-xl-2" )}} + {{ wtf.form_field( owned_form.delete, horizontal_columns=('xl', 2, 2), class="btn btn-danger offset-xl-1 col-xl-2" )}} +
+
+
+{% endblock main_content %} diff --git a/templates/owneds.html b/templates/owneds.html new file mode 100644 index 0000000..4e61e30 --- /dev/null +++ b/templates/owneds.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block main_content %} +

Owned List

+ + + + + + {% for owned in owneds %} + + {% endfor %} + +
Name
{{owned.name}}
+{% endblock main_content %} diff --git a/templates/rating.html b/templates/rating.html new file mode 100644 index 0000000..06fb106 --- /dev/null +++ b/templates/rating.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} {% block main_content %} +

Rating

+
+ + {% if message|length %} +
+ {{message}} +
+ {% endif %} +
+
+ {{ wtf.form_field( rating_form.id, form_type='inline' ) }} +
+ {{ wtf.form_field( rating_form.name, form_type='horizontal', horizontal_columns=('xl', 2, 10), style="width:100%" ) }} +
+
+

+
+ {{ wtf.form_field( rating_form.submit, horizontal_columns=('xl', 2, 2), class="btn btn-primary offset-xl-1 col-xl-2" )}} + {{ wtf.form_field( rating_form.delete, horizontal_columns=('xl', 2, 2), class="btn btn-danger offset-xl-1 col-xl-2" )}} +
+
+
+{% endblock main_content %} diff --git a/templates/ratings.html b/templates/ratings.html new file mode 100644 index 0000000..871a7c2 --- /dev/null +++ b/templates/ratings.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block main_content %} +

Ratings

+ + + + + + {% for rating in ratings %} + + {% endfor %} + +
Name
{{rating.name}}
+{% endblock main_content %}