I'm trying to add a script which directs me to the same page with refreshed content.
I'm using an sqlite3 database for my code and when i try it only works with the page refresh. This is one of my SQL structures.
CREATE TABLE classes (
model_id TEXT NOT NULL,
class_number INTEGER,
class_name TEXT,
FOREIGN KEY(model_id) REFERENCES models(model_id)
);
The problem is this is my flask route i use this kind of structure:
@app.route("/model/<model_id>",methods=["POST","GET"])
@login_required
def view_model(model_id):
...
with sqlite3.connect("database.db") as con:
.
.
.
return render_template("train.html",
categories=CATEGORIES,
model_id=model_id,
model=model,
classes=classes,
images=images,
istrained=istrained,
test_image=test_image
)
images=images)
And when ijust need to change the SQL just like in this route i need to either redirect(f"/model/{model_id}") or return "",402.In the first case all the page reloads and since the sql change it successfully reloads all the page.Also when i try the second one nothing applies since the classes is defined in the first route.
@app.route("/add_class/<model_id>",methods=["POST","GET"])
@login_required
def add_class(model_id):
with sqlite3.connect("database.db") as con:
con.row_factory = sqlite3.Row
db = con.cursor()
result = db.execute("SELECT MAX(class_number) FROM classes WHERE model_id = ?", (model_id,)).fetchone()
max_num = result[0] if result and result[0] is not None else 0
default_num = int(max_num +1)
default_name = "Class " + str(max_num + 1)
db.execute("INSERT INTO classes (model_id,class_name,class_number) VALUES(?,?,?)",
(model_id,default_name,default_num))
con.commit()
return redirect(f"/model/{model_id}")
I need to find a way to change the content but without all the page reloading.And want to know are there any ways to solve this problem without javascript.
Flask doesn't have special functions to send data from browser to server without reloading page.
It needs to use JavaScript
and standard function fetch()
(or external modules like jQuery
) to send data to serve and get result (without reloading paga) and eventually update only some part of page.
fetch
can use GET
, POST
or any other method. It can send text
, HTML
, JSON
, image
, etc.
Flask can sends back HTML
, JSON
or even image and JavaScript
can use it to update HTML
on page.
Flask can use request.method
to detect if it is POST
request, and request.is_json
to check if it is JSON request (if only fetch
sends header "Content-Type": "application/json"
)
Minimal working code which use fetch
to send POST
to /add_model/<model_id>
and Flask
sends back JSON
with {'status': ...}
and JavaScript
displays this status on page.
I also added code which tests if it works with @login_required
functions.
It needs credentials: 'include'
in fetch()
from flask import Flask, request, jsonify, render_template_string, redirect
from flask_login import LoginManager, UserMixin, login_required, login_user, logout_user
class User(UserMixin):
def __init__(self, id, email, password):
self.id = id
self.email = email
self.password = password
# dict key is the same as User.id
users = {'007': User('007', 'james_bond@mi6.gov.uk', 'license_to_kill')}
app = Flask(__name__)
app.secret_key = "super secret string" # Change this!
login_manager = LoginManager()
login_manager.init_app(app)
@login_manager.user_loader
def load_user(user_id):
print('load_user:', user_id, users.get(user_id))
return users.get(user_id)
@app.route('/login')
def login():
user = users.get('007')
print('login:', user)
login_user(user)
print('redirect:', '/')
return redirect('/')
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect('/')
@app.route('/')
def index():
return render_template_string("""
<script type=text/javascript>
function send_data(model_id, method) {
fetch("/add_model/" + model_id, {
method: method, // "POST"
// body: JSON.stringify({"username": "example" }), // if you need send JSON data in body
headers: {
// "Content-Type": "application/x-www-form-urlencoded", // sending <form>
"Content-Type": "application/json", // if you want to use `reques.is_json` in Flask
// "X-Requested-With": "XMLHttpRequest" // popular header for AJAX requests
},
credentials: 'include', // use cookies to access @login_required functions
}).then((response) => {
if (!response.ok) { // same as response.status < 200 || >= 300
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json(); // if you send JSON data
//return response.text(); // if you send text or HTML
}).then((data) => {
//console.log(data); // display message in DevTool console
document.getElementById("result").innerHTML = `model #${model_id}: ${data['status']}`; // use ` ` to format string with variables
}).catch((err) => {
console.log('Fetch problem: ' + err.message);
console.log(err)
document.getElementById("result").innerHTML = 'Fetch problem: ' + err.message;
});
}
</script>
{% if current_user.is_authenticated %}
<p>Logged in as: {{ current_user.id }} <a href="{{ url_for('logout') }}">Logout</a></p>
{% else %}
<p>You are not logged in. <a href="{{ url_for('login') }}">Login</a></p>
{% endif %}
{% for model_id in range(1, 6) %}
<button onclick="send_data({{ model_id }}, 'POST')">Add model #{{ model_id }} (POST)</button>
<button onclick="send_data({{ model_id }}, 'GET')">Add model #{{ model_id }} (GET)</button>
</br>
{% endfor %}
<div id="result"></div>
""")
@app.route('/add_model/<model_id>', methods=['GET', 'POST'])
@login_required
def add_model(model_id):
print(f'add_model: {model_id} | method: {request.method} | is_json: {request.is_json}')
if request.method == 'POST' and request.is_json:
return jsonify({'status': 'OK'})
else:
return jsonify({'status': f'Wrong Method {request.method}'})
if __name__ == "__main__":
#app.debug = True
app.run(host='0.0.0.0') #, port=8000) #, debug=True)