Flask Study Note 1

Views: 1273
Wrote on May 14, 2020, 3:24 p.m.

Django
Pro: Large and complete in function, ORM models, modelForm, admin, csrf and session etc included.
Con: high resource use

Flask web
Pro: Short and strong. ORM:x , Form:x , admin:x, csrf:x, but session:√, large thrid-party community
Con: Relatively poor stability compared with Django, most of the modules are from third-parties.

Tornado
Pro: Asynchronous, IO, non-blocking, native websocket
Con: nothing build-in

Flask at first sight

from flask import Flask
app = Flask(__name__)

@app.route("/",methods=["GET","POST"])
def index():
    return ""

app.run()

Response

#HTTPResponse
return "Hello World!"
#render
return render_template("login.html")
#redirect
return redirect("/login")
# return streaming binary data, like image, video, audio etc
return send_file()

# this responses content-type: application/json in Response Headers
return jsonify()
# json.dumps() does the same job but returns text/html

Request

from flask import request

-`request.method` request method
-`request.form` all data submitted thru form
 -`request.form.to_dict()`
-`request.args` all argument in url, like `id` and `age` from `url?id=666&age=84`
-`request.json` where data stored when Content-Type: application/json
-`request.data` where data stored when Content-Type can not be parsed
-`request.url` request url 'http://127.0.0.1:5000'
-`request.path` route add '/login'
-`request.host` localhost:5000
-`request.host_url` http://localhost:5000/

If we have a form like this:

<form action="?id=666&age=84" method="POST">
    <p><input type="text" name="username"></p>
    <p><input type="password" name="pwd"></p>
    <input type="submit" value="Login">
</form>

the request.values returns both GET and POST data:

CombinedMultiDict([ImmutableMultiDict([('id', '666'), ('age', '84')]), ImmutableMultiDict([('username', 'tongye'), ('pwd', 'this is a password')])])

the request.values.to_dict() gives us:

{'username': 'tongye', 'pwd': 'password', 'id': '666', 'age': '84'}
// if a key exists in both get and post, the one in post would be replaced by get, url data replaces the form data

When a file is submitted

 <form action="?id=666&age=84" method="POST" enctype="multipart/form-data">
    <p><input type="text" name="username"></p>
    <p><input type="password" name="pwd"></p>
    <p><input type="file" name="myFile"></p>
    <input type="submit" value="Login">
  </form>

request.file give us:

ImmutableMultiDict([('myFile', <FileStorage: 'picture.jpg' ('image/jpeg')>)])

We can save submitted files to server

  if request.method == "POST":
        picture = request.files.get("myFile")
        picture.save(picture.filename)

Jinja2

Three ways to get data

// person = {"name":"tongye", "age":18, "gender":"male"}
<td>{{ person.name }}</td>
<td>{{ person.get("age") }}</td>
<td>{{ person["gender"] }}</td>

// family = [
//    {"name":"sommer", "age":2, "gender":"female"},
//    {"name":"sydnie", "age":2, "gender":"female"},
//    {"name":"tongye", "age":18, "gender":"male"}
// ]
<td>{{ family.2.name }}</td>
<td>{{ family[2].get("age") }}</td>
<td>{{ family.2["gender"] }}</td>

// family_dict = {
//    1: {"name":"sommer", "age":2, "gender":"female"},
//    2: {"name":"sydnie", "age":2, "gender":"female"},
//    3: {"name":"tongye", "age":18, "gender":"male"}
// }
{% for id, member in family_dict.items() %}
    <tr>
      <td>{{ id }}</td>
      <td>{{ family_dict[id].name }}</td>
      <td>{{ family_dict.get(id)["age"] }}</td>
      <td>{{ family_dict[id]["gender"] }}</td>
    </tr>
{% endfor %}

template_global()

Just like the simple_tag in Django

# app.py
@app.template_global()
def sum_up(a, b, c):
    return a+b+c
// index.html
{{ sum_up(6, 7, 8) }} // 21

template_filter()

# app.py
@app.template_filter()
def axb(a,b):
    return a*b
// index.html
{{ sum_up(1,3,2) | axb(7) }} //42

Macro

{% macro my_input(na, tp) %}
  <input type="{{ tp }}" value="{{ na }}">
{% endmacro %}

{{ my_input("Hello World!", "textarea") }} // a textarea with value "Hello World!" shown
{{ my_input("Login", "submit") }} // a login button

Session

Flask's sessions are client-side sessions. Any data that you write to the session is written to a cookie and sent to the client to store. The client will send the cookie back to the server with every request, that is how the data that you write in the session remains available in subsequent requests. The data stored in the cookie is cryptographically signed to prevent any tampering. The SECRET_KEY setting from your configuration is used to generate the signature, so the data in your client-side sessions is secure as long as your secret key is kept private. Note that secure in this context means that the data in the session cannot be modified by a potential attacker. The data is still visible to anybody who knows how to look, so you should never write sensitive information in a client-side session.

from flask import session
app.secret_key = "somekeys"
session["user"] = "tongye"
session.get("user")

Example:

app.secret_key = "YouWillNeverGuessMySecretKey"

@app.route("/")
def index():
    if session.get('user'):
        print(session)
        return render_template("index.html", family_dict=family_dict)
    return redirect("/login")

@app.route("/login", methods=["GET", "POST"])
def login():
    # print(request.form.to_dict())
    if request.method == "GET":
        # print(request.form.get("username"))
        return render_template("login.html")
    if request.method == "POST":
        user_info = request.form.to_dict()
        if user_info.get("username") == "tongye" and user_info.get("pwd") == "123":
            session["user"] = user_info.get("username")
            return redirect("/")
        else:
            return render_template("login.html", msg="Wrong username or password")