ubuntu@c-test-node:~/C/w9/flask_demo$ ls
app.py tmplates
ubuntu@c-test-node:~/C/w9/flask_demo$ flask run
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
The Flask framework implements a particular paradigm, or way of thinking and programming. This paradigm, also implemented by other frameworks, is known as MVC, or Model–view–controller:
The controller contains our “business logic”, code that manages our application overall, given user input. In Flask, this will be our Python code in app.py.
The view includes templates and visuals for the user interface, like the HTML and CSS that the user will see and interact with.
The model is our application’s data, such as a SQL database or CSV file, which we haven’t yet used.
5. 保存数据
可以直接储存在内存中(Python程序):
...
REGISTRANTS = {}
...
@app.route("/register", methods=["POST"])
def register():
# Validate name
name = request.form.get("name")
if not name:
return render_template("error.html", message="Missing name")
# Validate sport
sport = request.form.get("sport")
if not sport:
return render_template("error.html", message="Missing sport")
if sport not in SPORTS:
return render_template("error.html", message="Invalid sport")
# Remember registrant
REGISTRANTS[name] = sport
# Confirm registration
return redirect("/registrants")
可以直接储存在数据库中:
...
db = SQL("sqlite:///froshims.db")
...
@app.route("/register", methods=["POST"])
def register():
# Validate submission
name = request.form.get("name")
sport = request.form.get("sport")
if not name or sport not in SPORTS:
return render_template("failure.html")
# Remember registrant
db.execute("INSERT INTO registrants (name, sport) VALUES(?, ?)", name, sport)
# Confirm registration
return redirect("/registrants")
@app.route("/deregister", methods=["POST"])
def deregister():
# Forget registrant
id = request.form.get("id")
if id:
db.execute("DELETE FROM registrants WHERE id = ?", id)
return redirect("/registrants")
6. 发送邮件
We can even email users with another library, flask_mail。
# Implements a registration form, confirming registration via email
import os
import re
from flask import Flask, render_template, request
from flask_mail import Mail, Message
app = Flask(__name__)
# Requires that "Less secure app access" be on
# https://support.google.com/accounts/answer/6010255
app.config["MAIL_DEFAULT_SENDER"] = os.environ["MAIL_DEFAULT_SENDER"]
app.config["MAIL_PASSWORD"] = os.environ["MAIL_PASSWORD"]
app.config["MAIL_PORT"] = 587
app.config["MAIL_SERVER"] = "smtp.gmail.com"
app.config["MAIL_USE_TLS"] = True
app.config["MAIL_USERNAME"] = os.environ["MAIL_USERNAME"]
mail = Mail(app)
...
It turns out that we can provide configuration details like a username and password and mail server, in this case Gmail’s, to the Mail variable, which will send mail for us.
In our register route, we send an email to the user with the mail.send() function from the flask_mail library:
@app.route("/register", methods=["POST"])
def register():
# Validate submission
name = request.form.get("name")
email = request.form.get("email")
sport = request.form.get("sport")
if not name or not email or sport not in SPORTS:
return render_template("failure.html")
# Send email
message = Message("You are registered!", recipients=[email])
mail.send(message)
# Confirm registration
return render_template("success.html")
To include the libraries we need, we’ll write a requirements.txt file with:
Flask
Flask-Mail
7. Sessions
7.1 Cookie
Sessions are how web servers remembers information about each user, which enables features like allowing users to stay logged in, and saving items to a shopping cart. These features require our server to be stateful, or having access to additional state, or information. HTTP on its own is stateless, since after we make a request and get a response, the interaction is completed.
It turns out that servers can send another header in a response, called Set-Cookie:
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: session=value
...
Cookies are small pieces of data from a web server that the browser saves for us. In many cases, they are large random numbers or strings used to uniquely identify and track a user between visits.
In this case, the server is asking our browser to set a cookie for that server, called session to a value of value.
Then, when the browser makes another request to the same server, it’ll send back the same cookie that the same server has set before:
GET / HTTP/1.1
Host: gmail.com
Cookie: session=value
通过这个方法能实现长久登陆。
7.2 flask_session
In Flask, we can use the flask_session library to help manage this for us:
<div data-gb-custom-block data-tag="extends" data-0='layout.html'></div>
<div data-gb-custom-block data-tag="block">
<div data-gb-custom-block data-tag="if" data-0='name' data-1='name'>
You are logged in as {{ session["name"] }}. <a href="/logout">Log out</a>.
<div data-gb-custom-block data-tag="else"></div>
You are not logged in. <a href="/login">Log in</a>.
</div>
</div>
We’ll configure the session library to use the server’s filesystem, and use session like a dictionary to store a user’s name. It turns out that Flask will use HTTP cookies for us, to maintain this session variable for each user visiting our web server.
Up until now, our interaction with JavaScript has been mostly limited to: push a button, something happens.
We still don't have to entirely reload our page, but there is still some degree of user interaction.
Ajax (formerly Asynchronous JavaScript and XML) allows us to dynamically update a webpage even more dynamically.
Central to our ability to asynchronously update our pages is to make use of a special JavaScript object called an XMLHttpRequest.
var xhttp = new XMLHttpRequest();
After obtaining your new object, you need to define its onreadystatechange behavior.
This is a function (typically an anonymous function) that will be called when the asynchronous HTTP request has completed, and thus typically defines what is expected to change on your site.
XMLHttpRequests have two additional properties that are used to detect when the page finishes loading.
The readyState property will change from from 0 (request not yet initialized) to 1, 2, 3, and finally 4 (request finished, response ready).
The status property will (hopefully!) be 200 (OK).
Then just make your asynchronous request using the open() method to define the request and the send() method to actually send it.
例子:
function ajax_request(argument){
var aj = new XMLHttpRequest();
aj.onreadystatechange = function (){
if (aj.readyState ==4 && aj.status ==200){
// TODO
}
};
aj.open("GET", /* url */, true);
aj.send();00
};
let input = document.querySelector('input');
input.addEventListener('input', async function() {
let response = await fetch('/search?q=' + input.value);
let shows = await response.json();
let html = '';
for (let id in shows) {
let title = shows[id].title.replace('<', '<').replace('&', '&');
html += '<li>' + title + '</li>';
}
document.querySelector('ul').innerHTML = html;
});
fetch('/search?q=' + input.value)会在后台发送GET请求。
Flask设置了这个路由:
@app.route("/search")
def search():
shows = db.execute("SELECT * FROM shows WHERE title LIKE ?", "%" + request.args.get("q") + "%")
return render_template("search.html", shows=shows)