Add table querying via form
This commit is contained in:
parent
6caca22472
commit
1aac68473d
26
Design.org
26
Design.org
|
@ -46,6 +46,13 @@ CLOSED: [2019-11-01 Fri 00:34]
|
||||||
- [X] Entity-Relationship
|
- [X] Entity-Relationship
|
||||||
** Implementation
|
** Implementation
|
||||||
*** TODO Backend [2/4] [50%]
|
*** TODO Backend [2/4] [50%]
|
||||||
|
**** TODO Flask Application [2/3] [66%]
|
||||||
|
- [ ] Plots with pandas
|
||||||
|
- [X] Login for admin
|
||||||
|
- [X] Tables with pandas
|
||||||
|
**** TODO Possible additions [1/2] [50%]
|
||||||
|
- [ ] Text search for glaciers
|
||||||
|
- [X] Form seach for a year
|
||||||
**** DONE Database [3/3] [100%]
|
**** DONE Database [3/3] [100%]
|
||||||
CLOSED: [2020-01-03 Fri 00:44]
|
CLOSED: [2020-01-03 Fri 00:44]
|
||||||
- [X] Connection
|
- [X] Connection
|
||||||
|
@ -56,15 +63,12 @@ CLOSED: [2020-01-08 Wed 03:18]
|
||||||
- [X] Select useful fiels
|
- [X] Select useful fiels
|
||||||
- [X] Convert PU to Country (ISO 3166)
|
- [X] Convert PU to Country (ISO 3166)
|
||||||
- [X] Insert into database
|
- [X] Insert into database
|
||||||
**** TODO Flask Application [1/4] [25%]
|
*** TODO Documentation [0/2] [0%]
|
||||||
- [ ] Arithmetic operations for yearly changes
|
- [ ] Code
|
||||||
- [ ] Tables with pandas
|
- [ ] Explanations (uid as Varchar, ORM)
|
||||||
- [ ] Plots with pandas
|
*** TODO Deployment [0/1] [0%]
|
||||||
- [X] Login for admin
|
- [ ] Virtualenv installation script
|
||||||
**** TODO Possible additions [0/2] [0%]
|
*** DONE Frontend [2/2] [100%]
|
||||||
- [ ] Text search for glaciers
|
CLOSED: [2020-01-09 Thu 11:09]
|
||||||
- [ ] Form seach for a year
|
|
||||||
*** TODO Frontend [1/2] [50%]
|
|
||||||
- [X] Flask-Bootstrap
|
- [X] Flask-Bootstrap
|
||||||
- [ ] Find CSS
|
- [X] Find CSS
|
||||||
*** TODO Documentation
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
from wtforms import BooleanField, PasswordField, SelectField, StringField, SubmitField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,3 +8,39 @@ class LoginForm(FlaskForm):
|
||||||
password = PasswordField("Password", validators=[DataRequired()])
|
password = PasswordField("Password", validators=[DataRequired()])
|
||||||
remember_me = BooleanField("Remember Me")
|
remember_me = BooleanField("Remember Me")
|
||||||
submit = SubmitField("Sign In")
|
submit = SubmitField("Sign In")
|
||||||
|
|
||||||
|
|
||||||
|
class YearForm(FlaskForm):
|
||||||
|
year_list = [
|
||||||
|
("2011", 2011),
|
||||||
|
("2012", 2012),
|
||||||
|
("2013", 2013),
|
||||||
|
("2014", 2014),
|
||||||
|
("2015", 2015),
|
||||||
|
("2016", 2016),
|
||||||
|
("2017", 2017),
|
||||||
|
("2018", 2018),
|
||||||
|
]
|
||||||
|
year = SelectField("Year", validators=[DataRequired()], choices=year_list)
|
||||||
|
submit = SubmitField("Search")
|
||||||
|
|
||||||
|
|
||||||
|
class IntervalForm(FlaskForm):
|
||||||
|
year_list = [
|
||||||
|
("2011", 2011),
|
||||||
|
("2012", 2012),
|
||||||
|
("2013", 2013),
|
||||||
|
("2014", 2014),
|
||||||
|
("2015", 2015),
|
||||||
|
("2016", 2016),
|
||||||
|
("2017", 2017),
|
||||||
|
("2018", 2018),
|
||||||
|
]
|
||||||
|
name = StringField("Glacier Name")
|
||||||
|
lower_bound = SelectField(
|
||||||
|
"First year", validators=[DataRequired()], choices=year_list
|
||||||
|
)
|
||||||
|
upper_bound = SelectField(
|
||||||
|
"Second year", validators=[DataRequired()], choices=year_list
|
||||||
|
)
|
||||||
|
submit = SubmitField("Search")
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from app import app
|
from app import app, db
|
||||||
from app.forms import LoginForm
|
from app.forms import LoginForm, YearForm, IntervalForm
|
||||||
from app.models import User
|
from app.models import User, Annual_Data, Glacier
|
||||||
from flask import flash, redirect, render_template, url_for, request
|
from flask import flash, redirect, render_template, url_for, request
|
||||||
from flask_login import current_user, login_user, logout_user, login_required
|
from flask_login import current_user, login_user, logout_user, login_required
|
||||||
from werkzeug.urls import url_parse
|
from werkzeug.urls import url_parse
|
||||||
|
from processing.tabulate import create_table
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
|
@ -53,9 +54,24 @@ def data():
|
||||||
return render_template("data.html", title="Data")
|
return render_template("data.html", title="Data")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/tables")
|
@app.route("/table_selection", methods=["GET", "POST"])
|
||||||
def tables():
|
def table_selection():
|
||||||
return render_template("data.html", title="Data")
|
form = YearForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
annual_data = (
|
||||||
|
db.session.query(Annual_Data).filter_by(year=form.year.data).statement
|
||||||
|
)
|
||||||
|
if annual_data is None:
|
||||||
|
flash("Invalid query, please try again")
|
||||||
|
return redirect(url_for("table_selection"))
|
||||||
|
table = create_table(annual_data)
|
||||||
|
return render_template("table.html", table=table, title="Table")
|
||||||
|
return render_template("table_selection.html", title="Data", form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/table")
|
||||||
|
def table():
|
||||||
|
return render_template("table.html", table=table, title="Table")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/plots")
|
@app.route("/plots")
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Hey, {{ current_user.username }}!</h1>
|
<h1 class="text-center">Hey, {{ current_user.username }}!</h1>
|
||||||
Do you want to nuke the database?
|
<p class="text-center">Do you want to nuke the database?</p>
|
||||||
<li><a href="{{ url_for('nuke') }}">Yes, I want to burn down the world</a></li>
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
<a href="{{ url_for('nuke') }}"><b>Yes</b>, I want to burn down the world</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
Nah, show me some cool <a href="{{ url_for('data') }}">data</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends 'bootstrap/base.html' %}
|
{% extends 'bootstrap/base.html' %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
IGDB
|
{% if title %}{{ title }} - IGDB{% else %}IGDB{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Hey, {{ current_user.username }}!</h1>
|
<h1 class="text-center">What do you want to check out?</h1>
|
||||||
Wanna check out some cool data?
|
<li>
|
||||||
<li><a href="{{ url_for('tables') }}"></a></li>
|
<p class="text-center">
|
||||||
<li><a href="{{ url_for('plots') }}"></a></li>
|
<a href="{{ url_for('table_selection') }}">Tables</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
<a href="{{ url_for('plots') }}">Plots</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Table</h1>
|
||||||
|
{{ table|safe }}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Table selection</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
{{ wtf.quick_form(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{% endblock %}
|
|
@ -1,19 +1,9 @@
|
||||||
|
from app import db
|
||||||
from app.models import Annual_Data, Glacier, User
|
from app.models import Annual_Data, Glacier, User
|
||||||
from database.constants import DB_NAME, DB_PW, DB_USER
|
|
||||||
from pandas import DataFrame, read_csv
|
from pandas import DataFrame, read_csv
|
||||||
from sqlalchemy import create_engine, engine
|
|
||||||
|
|
||||||
|
|
||||||
def create_connection() -> engine:
|
def create_dataframes() -> {DataFrame}:
|
||||||
host = "localhost:3306"
|
|
||||||
connection_uri = "mysql+pymysql://{user}:{pw}@{url}/{db}".format(
|
|
||||||
user=DB_USER, pw=DB_PW, url=host, db=DB_NAME
|
|
||||||
)
|
|
||||||
engine = create_engine(connection_uri)
|
|
||||||
return engine
|
|
||||||
|
|
||||||
|
|
||||||
def create_dataframes() -> DataFrame:
|
|
||||||
files = {
|
files = {
|
||||||
"glacier": "../data/glacier.csv",
|
"glacier": "../data/glacier.csv",
|
||||||
"annual_data": "../data/annual_data.csv",
|
"annual_data": "../data/annual_data.csv",
|
||||||
|
@ -25,19 +15,18 @@ def create_dataframes() -> DataFrame:
|
||||||
return df_list
|
return df_list
|
||||||
|
|
||||||
|
|
||||||
def insert_data(df_list, conn):
|
def insert_data(df_list):
|
||||||
models = [Glacier, Annual_Data, User]
|
models = [Glacier, Annual_Data, User]
|
||||||
for model in models:
|
for model in models:
|
||||||
if model.query.first() is not None:
|
if model.query.first() is not None:
|
||||||
return
|
return
|
||||||
for key, value in df_list.items():
|
for key, value in df_list.items():
|
||||||
value.to_sql(key, con=conn, index=False, if_exists="append")
|
value.to_sql(key, con=db.engine, index=False, if_exists="append")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
conn = create_connection()
|
|
||||||
df_list = create_dataframes()
|
df_list = create_dataframes()
|
||||||
insert_data(df_list, conn)
|
insert_data(df_list)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from app import app
|
from app import app
|
||||||
from database import db_setup, export, parser
|
from database import db_setup, export, parser
|
||||||
|
from processing import tabulate
|
||||||
|
|
||||||
db_setup.main()
|
db_setup.main()
|
||||||
parser.main()
|
parser.main()
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
from app import db
|
||||||
|
from pandas import DataFrame, read_sql, wide_to_long
|
||||||
|
|
||||||
|
|
||||||
|
def create_dataframe(query) -> DataFrame:
|
||||||
|
df = read_sql(sql=query, con=db.engine)
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def render_table(df) -> str:
|
||||||
|
table = df.to_html(classes=["table-bordered", "table-striped", "table-hover"])
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
def create_table(query) -> str:
|
||||||
|
df = create_dataframe(query)
|
||||||
|
html_table = render_table(df)
|
||||||
|
return html_table
|
Loading…
Reference in New Issue