Browse Source

queries with max date

master
Juni Kim 2 years ago
parent
commit
2fc6083e80
  1. 6
      2-5-23.txt
  2. 69
      app.py
  3. 68
      templates/search.html

6
2-5-23.txt

@ -2,11 +2,11 @@
- Show how to make a network request in R to the server - Show how to make a network request in R to the server
- Version Control (what date a compound was added) - Version Control (what date a compound was added)
- createdAt, but configurable.
- createdAt, but configurable. DONE
- Compare the database to the list of compunds and you only want compounds - Compare the database to the list of compunds and you only want compounds
from that date or before?
from that date or before? DONE
- Emphasizing Local? - Accessible through a url.
- Emphasizing Local? - Accessible through a url. DONE, all fields accessible.
- Shiny app - Shiny app
- Permissions System (revoke, access API keys) - Permissions System (revoke, access API keys)

69
app.py

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from datetime import date
from flask import Flask, render_template, session, request, abort, redirect, url_for, jsonify from flask import Flask, render_template, session, request, abort, redirect, url_for, jsonify
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import inspect, and_ from sqlalchemy import inspect, and_
@ -86,6 +87,7 @@ class Chemical(db.Model):
msms_detected = db.Column(db.Boolean) msms_detected = db.Column(db.Boolean)
msms_purity = db.Column(db.Float) msms_purity = db.Column(db.Float)
# serialized into datetime.date
createdAt = db.Column(db.Date) createdAt = db.Column(db.Date)
@ -123,13 +125,15 @@ def admin_create():
if request.method == "GET": if request.method == "GET":
return render_template("register.html") return render_template("register.html")
else: else:
username, pw = request.form.get('username'), request.form.get('password')
username, pw = request.form.get(
'username'), request.form.get('password')
if username is None or pw is None: if username is None or pw is None:
return render_template("register.html", fail="Invalid Input.") return render_template("register.html", fail="Invalid Input.")
elif db.session.execute(db.select(Admin).filter_by(username=username)).fetchone(): elif db.session.execute(db.select(Admin).filter_by(username=username)).fetchone():
return render_template("register.html", fail="Username already exists.") return render_template("register.html", fail="Username already exists.")
else: else:
db.session.add(Admin(username=username, password=Admin.generate_password(pw)))
db.session.add(
Admin(username=username, password=Admin.generate_password(pw)))
db.session.commit() db.session.commit()
return render_template("register.html", success=True) return render_template("register.html", success=True)
@ -137,7 +141,8 @@ def admin_create():
@app.route('/admin/login', methods=['GET', 'POST']) @app.route('/admin/login', methods=['GET', 'POST'])
def admin_login(): def admin_login():
if request.method == "POST": if request.method == "POST":
username, pw = request.form.get('username', ''), request.form.get('password', '')
username, pw = request.form.get(
'username', ''), request.form.get('password', '')
if Admin.authenticate(username, pw): if Admin.authenticate(username, pw):
return render_template("login.html", success=True) return render_template("login.html", success=True)
else: else:
@ -184,7 +189,7 @@ def chemical_create():
def chemical_update(id: int): def chemical_update(id: int):
if not session.get('admin'): if not session.get('admin'):
abort(403) abort(403)
current_chemical:Chemical = Chemical.query.filter_by(id=id).one_or_404()
current_chemical: Chemical = Chemical.query.filter_by(id=id).one_or_404()
dct = object_as_dict(current_chemical) dct = object_as_dict(current_chemical)
if request.method == "POST": if request.method == "POST":
form = ChemicalForm(**request.form) form = ChemicalForm(**request.form)
@ -206,7 +211,7 @@ def chemical_update(id: int):
def chemical_delete(id: int): def chemical_delete(id: int):
if not session.get('admin'): if not session.get('admin'):
abort(403) abort(403)
current_chemical:Chemical = Chemical.query.filter_by(id=id).one_or_404()
current_chemical: Chemical = Chemical.query.filter_by(id=id).one_or_404()
db.session.delete(current_chemical) db.session.delete(current_chemical)
db.session.commit() db.session.commit()
return render_template("delete_chemical.html", id=id) return render_template("delete_chemical.html", id=id)
@ -214,7 +219,7 @@ def chemical_delete(id: int):
@app.route("/chemical/<int:id>/view") @app.route("/chemical/<int:id>/view")
def chemical_view(id: int): def chemical_view(id: int):
current_chemical:Chemical = Chemical.query.filter_by(id=id).one_or_404()
current_chemical: Chemical = Chemical.query.filter_by(id=id).one_or_404()
dct = object_as_dict(current_chemical) dct = object_as_dict(current_chemical)
return render_template("view_chemical.html", id=id, chemical=dct) return render_template("view_chemical.html", id=id, chemical=dct)
@ -223,40 +228,42 @@ def chemical_view(id: int):
def chemical_all(): def chemical_all():
if not session.get('admin'): if not session.get('admin'):
abort(403) abort(403)
result = Chemical.query.all()
result: list[Chemical] = Chemical.query.all()
data = [] data = []
for x in result: for x in result:
data.append({"url": url_for("chemical_view", id=x.id), "name": x.name, "mz": x.final_mz, "rt": x.final_rt})
data.append({c.name: getattr(x, c.name) for c in x.__table__.columns})
return jsonify(data) return jsonify(data)
@app.route("/chemical/search")
@app.route("/chemical/search", methods=["POST"])
def search_api(): def search_api():
mz_min, mz_max = request.args.get('mz_min'), request.args.get('mz_max')
rt_min, rt_max = request.args.get('rt_min'), request.args.get('rt_max')
if (mz_min is None and mz_max is None) or (rt_min is None and rt_max is None):
return jsonify({"error": "invalid data"}), 400
query = request.json
if query is None:
return jsonify([])
for field in query:
query[field] = float(query[field])
mz_min, mz_max = query.get('mz_min'), query.get('mz_max')
rt_min, rt_max = query.get('rt_min'), query.get('rt_max')
year_max, month_max, day_max = int(query.get(
'year_max')), int(query.get('month_max')), int(query.get('day_max'))
try: try:
if mz_min is not None and mz_max is None:
mz_max = float(mz_min) + 3
elif mz_max is not None and mz_min is None:
mz_min = float(mz_max) - 3
if rt_min is not None and rt_max is None:
rt_max = float(rt_min) + 3
elif rt_max is not None and rt_min is None:
rt_min = float(rt_max) - 3
mz_min, mz_max = float(mz_min), float(mz_max)
rt_min, rt_max = float(rt_min), float(rt_max)
except ValueError:
return jsonify({"error": "invalid data"}), 400
mz_filter = and_(mz_max > Chemical.final_mz, Chemical.final_mz > mz_min)
rt_filter = and_(rt_max > Chemical.final_rt, Chemical.final_rt > rt_min)
mz_filter = and_(mz_max > Chemical.final_mz,
Chemical.final_mz > mz_min)
rt_filter = and_(rt_max > Chemical.final_rt,
Chemical.final_rt > rt_min)
date_filter = date(year_max, month_max, day_max) >= Chemical.createdAt
except ValueError as e:
return jsonify({"error": str(e)}), 400
result = Chemical.query.filter( result = Chemical.query.filter(
and_(mz_filter, rt_filter)
).limit(10).all()
and_(mz_filter, rt_filter, date_filter)
).limit(20).all()
data = [] data = []
for x in result: for x in result:
data.append({"url": url_for("chemical_view", id=x.id), "name": x.name, "mz": x.final_mz, "rt": x.final_rt})
data.append({"url": url_for("chemical_view", id=x.id),
"name": x.name, "mz": x.final_mz, "rt": x.final_rt})
return jsonify(data) return jsonify(data)

68
templates/search.html

@ -26,28 +26,55 @@
mz_max: 0, mz_max: 0,
rt_min: 0, rt_min: 0,
rt_max: 0, rt_max: 0,
// query parameters for the maximum date possible.
year_max: 2021,
month_max: 1,
day_max: 31,
// results
results: [], results: [],
error: null, error: null,
} }
}, },
methods: { methods: {
// methods // methods
async fetch_data() {
if (!(valid(this.mz_min) && valid(this.mz_max) && valid(this.rt_max) && valid(this.rt_min))) {
return
prepare_query() {
// validation
let query = {}
const fields = ["mz_min", "mz_max", "rt_min", "rt_max",
"year_max", "month_max", "day_max"]
for (let i = 0; i < fields.length; i++) {
const field = fields[i];
if (!valid(this[field])) {
console.log(query, field, this[field])
return null;
} else {
query[field] = this[field]
}
} }
const url = `/chemical/search?mz_min=${this.mz_min}&mz_max=${this.mz_max}&rt_min=${this.rt_min}&rt_max=${this.rt_max}`
fetch(url).then(res => {
return query
},
async fetch_data() {
const query = this.prepare_query()
if (query === null) return;
const api = `/chemical/search`;
fetch(api, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(query)
}).then(async res => {
if (res.status !== 200) { if (res.status !== 200) {
console.log(`Error Status, ${res.status}`) console.log(`Error Status, ${res.status}`)
const json = await res.json()
throw Error(json.error);
} }
return res.json() return res.json()
}).then(json => { }).then(json => {
this.results = json; this.results = json;
this.error = null; this.error = null;
}).catch(e => { }).catch(e => {
console.error(e);
this.error = true;
this.error = e.message;
}) })
} }
}, },
@ -67,7 +94,7 @@
<label for="mz_min">Minimum M/Z Ratio</label> <label for="mz_min">Minimum M/Z Ratio</label>
</td> </td>
<td> <td>
<input id="mz_min" type="number" name="mz_min" v-model="mz_min" @input="fetch_data()" value="0">
<input id="mz_min" type="number" name="mz_min" v-model="mz_min" value="0">
</td> </td>
</tr> </tr>
<tr> <tr>
@ -75,7 +102,7 @@
<label for="mz_min">Maximum M/Z Ratio</label> <label for="mz_min">Maximum M/Z Ratio</label>
</td> </td>
<td> <td>
<input id="mz_max" type="number" name="mz_max" v-model="mz_max" @input="fetch_data()" value="0">
<input id="mz_max" type="number" name="mz_max" v-model="mz_max" value="0">
</td> </td>
</tr> </tr>
<tr> <tr>
@ -83,7 +110,7 @@
<label for="mz_min">Minimum Retention Time</label> <label for="mz_min">Minimum Retention Time</label>
</td> </td>
<td> <td>
<input id="rt_min" type="number" name="rt_min" v-model="rt_min" @input="fetch_data()" value="0">
<input id="rt_min" type="number" name="rt_min" v-model="rt_min" value="0">
</td> </td>
</tr> </tr>
<tr> <tr>
@ -91,21 +118,32 @@
<label for="mz_min">Maximum Retention Time</label> <label for="mz_min">Maximum Retention Time</label>
</td> </td>
<td> <td>
<input id="rt_max" type="number" name="rt_max" v-model="rt_max" @input="fetch_data()" value="0">
<input id="rt_max" type="number" name="rt_max" v-model="rt_max" value="0">
</td>
</tr>
<tr>
<td>
<label for="mz_min">Maximum Date</label>
</td>
<td>
<input id="year_max" type="number" name="year_max"
v-model="year_max" placeholder="year">
<input id="month_max" type="number" name="month_max"
v-model="month_max" placeholder="month">
<input id="day_max" type="number" name="day_max"
v-model="day_max" placeholder="day">
</td> </td>
</tr> </tr>
</table> </table>
<!--
<br> <br>
<button @click="fetch_data()">Search</button> <button @click="fetch_data()">Search</button>
-->
</main> </main>
<hr> <hr>
{% raw %} {% raw %}
<div id="search"> <div id="search">
<div v-if="error" style="color: red;">
Uh Oh! There is an Error!
<div v-if="error !== null" style="color: red;">
Uh Oh! There is an Error! {{error}}
</div> </div>
<div v-for="result in results"> <div v-for="result in results">
<a :href="result.url"> <a :href="result.url">

Loading…
Cancel
Save