The paper

In the last section, we wrote a crawler script to grab news and save it into the MySQL database at 8:00 a.m. every day. DataGrip directly connected to the database, you can view the crawl to the news. But it’s not the final form we want. I wish news filtering could be done directly on the phone, instead of having to open up the computer, open up the DataGrip black page, filter, copy and paste every time. Before I write this APP, I need to learn something about the Web, write some interfaces. There are two popular flasks in Python and Django, and I chose the lighter Flask. In writing how to Get Rich in Python in a few days, some of my classmates wrote me that I didn’t have Flask’s tutorial recommendations. In this section we’ll look at Flask, and in the next section we’ll look at using Flask to write apis, static pages, and generate public article styles directly. Content is more, more boring, suggested to collect slowly after watching ~


Flask introduction

A lightweight “microkernel” Web application framework, WSGI suite based on Werkzeug implementation and Jinja2 template engine, with a compact kernel, easy to expand and less learning cost, that is, it is possible to develop a simple website.

Related documents:

  • Flask’s official website: Flask.pocoo.org/
  • Flask Github Warehouse: github.com/pallets/fla…
  • Flask Official documentation: flask.pocoo.org/docs/1.0
  • Flask official document (Chinese version) : dormousehole readthedocs. IO/en/latest /
  • Flask Learning Resources: github.com/humiaozuzu/…

2. Flask development environment construction

Install the PIP command directly:

pip install flask
Copy the code

Note the difference between a “global installation” and a “virtual installation”. Many readers have asked this question before:

PIP install XXX has been executed on the command line, but pycharm is still not found.

There are two alternative solutions to this:

  • Option 1: Execute the PIP install command on the PyCharm terminal

  • Option 2: Select Inherit Global Stie-Packages

Personally, I prefer the first option. To solve the problem of maintaining different versions for different projects, Python uses the concept of a virtual environment. Installing third-party packages in a virtual environment only affects the virtual environment, and the global Python interpreter is not affected. In Python3, the virtual environment has become a built-in module. An example of creating a file with the virtual environment is as follows:

mkdir Test
cd Test
python -m venv venv
Copy the code

After executing the above command, Python will run the venv package to create a virtual venv environment with two venv arguments:

  • The name of the Python virtual environment package, fixed to venv
  • The name applied to this particular virtual environment can be changed to whatever you like, but I prefer to call it venv. When switching to a different project, you can quickly find the corresponding virtual environment.

After a virtual environment is created, you need to activate it before entering it. Run the following command to activate the virtual environment:

source venv/bin/activate
Copy the code

When the virtual environment is activated, the environment configuration of the terminal session is changed. When you type Python or PIP, you are actually calling the Python interpreter in the virtual environment. One application scenario: Open multiple terminals to debug multiple applications. Each terminal window can activate different virtual environments without interfering with each other.

Note: if you are using Python2 or Windows, if you want to use a virtual environment, install a wave of virtualenvwrapper using the PIP install virtualenvwrapper command. Then create the virtual environment: virtualenv venv, and finally activate the virtual environment: venv\Scripts\activate.bat.


A simple Hello Flask

Create a new hello.py script that looks like this:

# coding=utf-8
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello Flask!"

if __name__ == "__main__":
    app.run()
Copy the code

Type the following command on the terminal to execute the script:

python hello.py
Copy the code

After the command is run, you can see the following output:

Open your browser: http://127.0.0.1:5000 and you’ll see Hello Flask!

Once the service is started, it will poll, wait and process the request until the program is terminated, or simply press Ctrl+C to stop. Parsing a wave of code line by line:

  • Line 1: Declares the encoding syntax of the Python source file. This information is later used by the Python parser to parse the source file, generally using UTF-8.
  • Line 2: Introduce the Flask class.
  • Line 4: instantiates a Flask class instance app, which receives a package or module name as an argument, usually passed in directly__name__And letflask.helpers.get_root_pathThe function determines the root directory of the program by passing in this name to get the directories for static and template files.
  • Line 6-8: the app:route decorator saves the relationship between the URL and the executed view function to the app.url_map property. Flask instance executes the view function Hello () when the browser accesses the root address of the server program (“/”), and returns: Hello Flask!
  • Line 10: The code in this judgment is not executed when other files reference this file.
  • Line 11: Flask only listens on local 127.0.0.1 address and 5000 port by default. If you want to change the port, you pass in “port= port number”. If you want to support remote access, you pass in “host=”0.0.0.0”. Simply pass in the parameter “debug=True” and when debug mode is enabled, the server will automatically reload the code after modification and provide a debug page that can obtain the error context and executable code when errors occur.

Flask-script module

This module is used to manipulate Flask from the command line, using the command line to pass parameters, not just through the app.run() function. This module can be installed directly with the PIP command:

pip install flask-script
Copy the code

Create a new manage.py file:

from flask_script import Manager
from flask import Flask

app = Flask(__name__)
manager = Manager(app)

if __name__ == '__main__':
    manager.run()
Copy the code

Then on the command line type:

Python manage.py runserver -h IP -p portCopy the code

Other parameters include -d (debug mode is enabled), -r (code is automatically loaded after modification), –help (view help information).


5. Routing and Views

The above:

@app.route("/")
def hello():
    return "Hello Flask!"
Copy the code

Defines the mapping between urls and Python functions, called routing.

0x1 Dynamic Route

Sometimes, there may be urls with the same rules, such as:

app.route("/login")
app.route("/register")
Copy the code

We can abstract this type of URL into a URL pattern as shown in the following example:

@app.route('/<do>')
def hello(do) :return "

Current request: %s

"
% do Copy the code

Flask supports dynamic routing. The dynamic part of the Flask is a string by default. You can also specify the parameter type, such as only accepting integers: <int: ID >.

The field tag describe The sample
string By default, accept any text without a slant bar “/” <string:name>
int The integer <in:id>
float Floating point Numbers <float:price>
path Similar to string, but also accepts slashes <path:address>
uuid Only UUID strings are accepted <string:uuid>
any Multiple paths can be specified, but parameters are passed in <any(int,string):params>

One other thing to note: unique urls, such as the following, represent two different urls:

CodingBoy.io/article/
CodingBoy.io/article
Copy the code

0 x2 URL structure

In Flask, a URL can be constructed using the url_for() function, which takes a view function name as the first parameter and a named parameter for the variable part of the corresponding URL rule. The unknown variable part is added to the end of the URL as the query parameter. It is important to note that this is a function, not the path !!!! in the route Building with functions, rather than string concatenation, serves two main purposes:

  • If you need to change the URL in the future, you only need to change the URL once rather than replace it everywhere;
  • URL builds automatically escape special characters and Unicode data without us handling them ourselves;

The following is an example:

with app.test_request_context():
    print(url_for('hello', uid=1))
    print(url_for('hello', uid=2, kind='test'))
Copy the code

The following output is displayed:

/? uid=1 /? uid=2&kind=%E6%B5%8B%E8%AF%95Copy the code

If you want to generate an absolute path, add the “_external=True” argument.

Note: test_request_context can generate a request context in interactive mode, without app.run() running the project, or Falsk context if executed directly

0x3 Request method qualification

HTTP supports multiple request methods. By default, a route responds only to a GET request. If you don’t believe it, you can use PostMan to send a POST request to the interface.

The response code is 405, indicating that this request method is not allowed to request this URL. You can directly set the methods parameter in the app.route decorator to change it. The following is an example of the modified code:

@app.route("/", methods=['GET'.'POST'])
def hello():
    return "Hello Flask!"
Copy the code

Other request methods are also supported: PUT, HEAD, DELETE, OPTIONS, and PATCH, separated by commas.


6, templates,

In Web development, we often use template engines. What is a template? This is a file that contains the response text and identifies the dynamic part with placeholders (variables) that tell the template engine its value needs to be taken from the data being used.

0x1 Relationship between views and templates

In the previous example, the view function’s primary role was to generate the response to the request, whereas in real development, the view function has two roles: “process the business logic” and “return the response content.” In large projects, putting business logic and presentation together can increase code complexity and maintenance costs. The template’s job is to “take responsibility for the part of the view function that returns the response, making the code uncoupleable and unstructured.” Replacing variables with their real values and returning the resulting string is a process called “rendering.” Flask uses the template engine “Jinja2” by default to render templates.

0 x2 Jinja2 syntax

Using a simple example to introduce templates, here is a simple program that does not use templates:

# coding=utf-8
from flask import Flask

app = Flask(__name__)
@app.route("/<user>")
def hello(user):
    if user == 'admin':
        return "

Administrator, hello!

"

else: return "< h1 > % s, hello! " % user if __name__ == "__main__": app.run() Copy the code

Flask then uses the Jinja2 template for overwriting. By default, Flask looks for templates in the project’s Templates subfolder, so we create a templates folder and then create an index.html, which looks like this:

{{name}}, hello!

"

Copy the code

Modify the hello.py file as follows:

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/<user>")
def hello(user):
    if user == 'admin':
        return render_template("index.html", user="Administrator")
    else:
        return render_template("index.html", user=user)

if __name__ == "__main__":
    app.run()
Copy the code

Run hello.py and type the following address in the browser. The output is as follows:

http://127.0.0.1:5000/admin     Hello, administrator!
http://127.0.0.1:5000/jay       Hello Jay!
Copy the code

This is a simple example of how to use a template. By calling Flask’s render_template function, a template is generated. The first parameter is the name of the template, followed by key-value pairs that represent the actual values of the variables in the template. The syntax for a wave of Jinja2 is explained in detail:

  • 1. The variable

Jinja2 uses **{{variable name}}** to represent a variable, and can use complex types such as lists, fields, or objects in addition to basic data types, as shown in the following example:

<h1> Account: {{user['name'}}, password: {{user['passwd']}}Copy the code
  • 2. Control structure

Jinja2 provides a variety of control structures, such as common judgment and loop structures, for modifying the rendering flow of templates. We put the above logic into the template as shown in the following example:

{# comment, not output to browser #}
{% if user == 'admin' or user == 'Administrator'%} <h1> Administrator, hello! </h1> {%else%} <h1> {{user}} </h1> {% endif %} {# loop print #}
{% for num in num_list %}
    <h2>{{ num }}</h2>
{% endfor %}
Copy the code

Next modify the hello.py file:

@app.route("/<user>")
def hello(user):
    return render_template("index.html", user=user, num_list=[1, 2, 3])
Copy the code

Type a different URL and the corresponding browser output is as follows:

http://127.0.0.1:5000/admin administrator, hello! 1 2 3 http://127.0.0.1:5000/jay jay, hello! 1 2 3Copy the code
  • 3. The macro

In Python, if you have some very common code, it is customary to extract it into a function. In Jinji2, you can implement it using macros. The syntax is as follows:

# to create macros{% end macro %}# call macros{{key=value}}Copy the code

If there are many macros, you can pull them into separate HTML and import them.

{% import 'xxx.html'As alias %} {{alias. Tag name (key=value)}}Copy the code
  • 4. Template inheritance

Another way to reuse code: template inheritance. Like class inheritance in Python, you need a base template that identifies a code block with {% block XXX %}{% endblock %}, which can be overridden in submodules. A code example is as follows:

# base template: base.html<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="UTF-8"> {% block head %} <title>{% block title %} Title {% endblock %} </title> {% endblock %} </head> <body> {% block body %}  {% endblock %} </body> </html># Subtemplate: son.html
{% extends "base.html"%} {% block title %}Son{% endblock %} {% block head %} {{super()}} {% endblock %} {% block body %} <h1>Hello Flask! </h1> {% endblock %}Copy the code

Code description:

The first line of code uses the extends command to indicate that the template inherits from base.html, and then overrides the title, head, and body blocks, with the super() function above to retrieve the original contents of the base template.

  • 5.inclue

A template can be included with the include statement, and the included template will be added to the position of the include statement during rendering, as shown in the following example:

{% include 'header.html' %}
Copy the code

Alternatively, you can use the “Ignore Missing” flag, which Jinja2 will ignore if the template does not exist, as shown in the following example:

{% include 'header.html' ignore missing %}
Copy the code
  • 6. The assignment

An assignment can be made using the set tag as shown in the following example:

{% setB = 1,2} <h1>{{a}}{{b}}</h1>Copy the code
  • 7. Built-in filters

Filters are essentially functions that sometimes need to be modified, formatted, or evaluated between variables. There are some Python methods that cannot be called directly from a template, so you can use filters. The template’s filter supports chain calls:

{{ "hello flask"| reverse | upper}},Copy the code

This code is inverted + to uppercase. Common built-in filters are strings and lists. String manipulation filters are shown in the following table:

The filter describe
safe Disable escape
capitalize Change the first letter of a variable value to uppercase and the rest to lowercase
lower Convert the value to lowercase
upper Convert the value to uppercase
title Capitalize the first letter of each word in the value
reverse String inversion
format Formatted output
striptags Remove all HTML tags from the value before rendering
truncate String truncation

List operation filters are shown in the following table:

The filter describe
first Take the first element
last Take the last element
length Get the list length
sum The list of sum
sort List ordering
  • 8. Customize filters

Write directly in the py file with the following code example:

# 1. Define filters
def do_listreverse(li):
    temp_li = list(li)
    temp_li.reverse()
    return temp_li

# 2. Add custom filters
app.add_template_filter(do_listreverse, 'listreverse')
Copy the code

Conclusion:

Macro, inheritance and inclusion are used to implement code reuse, macro function is similar to function, can pass parameters, need to define call; The essence of inheritance is code replacement, which is generally used to achieve repeated and unchanging areas in multiple pages. Include directly renders the entire target template file.


7. Request and response

In Flask, HTTP requests are wrapped as Request objects, and HTTP responses are wrapped as Response objects. Flask’s logic for application development is therefore based on these two objects.

0 x1 Request Request

Flask encapsulates the HTTP Request data forwarded by the WSGI server into a Request object. This object contains the Request information, which can be obtained by using the attributes in the following table.

attribute describe The data type
form Record the form data in the request. MultiDict
args Records the query parameters in the request. MultiDict
cookies Logs cookies in requests. Dict
headers Records the header in the request. EnvironHeaders
method Log the HTTP method used for the request. string
environ Record the environment variables that the WSGI server forwards. Dict
url Records the requested URL. string
  • 1. Read the query parameters of the Request

Flask stores the form data submitted by the browser as a GET request in the args of the Request instance, which can also be queried by the VALUES attribute.

# coding=utf-8
from flask import Flask, request, json

app = Flask(__name__)
@app.route("/index")
def index():
    return ' ''
      




' ' @app.route("/login") def login(): msg = "" if 'user' in request.args: msg += request.args['user'] + ':' msg += request.values.get('pawd'.' ') return msg if __name__ == "__main__": app.run(debug=True) Copy the code

After code to run, open: http://127.0.0.1:5000/index, the browser:

After enter the account password, jump to: http://127.0.0.1:5000/login? User =zpj&pawd=123

  • 2. Read the form data of request

Flask stores form data submitted by the browser as a GET request in the form of the Request instance, which can be read by using the [] operator. Read code example as follows:

# coding=utf-8
from flask import Flask, request, json

app = Flask(__name__)

@app.route("/index")
def index():
    return ' ''
      




' ' @app.route("/login", methods=['POST']) def login(): msg = "" msg += request.form['user'] + ':' msg += request.form['pawd'] return msg if __name__ == "__main__": app.run(debug=True) Copy the code

After code to run, open: http://127.0.0.1:5000/index, the browser:

After enter the account password, jump to: http://127.0.0.1:5000/login, the browser:

0 x2 Response Response

Corresponding to Request, Response is used to send a Response to the browser based on the result returned by the view function. The return value of the view function is automatically converted to a response object as follows:

  • 1. The return value is a valid response object and is returned directly from the view.
  • 2, the return value is a string, use a string and default parameters to create a string as the main body, return code is 200, the MIME type to text/HTML werkzeug. The wrappers. The Response Response object.
  • The return value is a tuple in which the element can provide additional information, but it must be in the form of response, status, or headers, and contain at least one element. The status value overwrites the status code. Headers can be a dictionary or a list as an additional header.
  • Flask assumes that the value returned is a valid WSGI program and transforms it into a request object via Response.force(rv. Request. Environ). In addition to returning by return, you can explicitly call the make_response function with the benefit of setting some additional information, as shown in the following example:
def hello():
    resp = make_response("Hello Flask!", 250).return resp
Copy the code

In addition, the API now all return JSON format, can be wrapped in Jsonify, modified sample code is as follows:

# coding=utf-8
from flask import Flask, make_response, jsonify
from werkzeug.wrappers import Response

app = Flask(__name__)

@app.route("/", methods=['GET'.'POST'])
def hello():
    resp = make_response({'code': '200'.'msg': 'Request successful'.'data': [{'data_1': ['data'.'data'].'data_2': ['data'.'data']}]})
    return resp

class JsonResponse(Response):
    @classmethod
    def force_type(cls, response, environ=None):
        if isinstance(response, dict):
            response = jsonify(response)
        return super(JsonResponse, cls).force_type(response, environ)

app.response_class = JsonResponse

if __name__ == "__main__":
    app.run(debug=True)
Copy the code

The request interface output is as follows:

{
    "code": "200"."data": [{"data_1": [
                "Data"."Data"]."data_2": [
                "Data"."Data"]}],"msg": "Request successful"
}
Copy the code

Flask’s JSON module dumps() function can also be used to convert arrays or dictionary objects to JSON strings, as shown in the following code:

data = {'code': '200'.'msg': 'Request successful'.'data': [{'data_1': ['data'.'data'].'data_2': ['data'.'data']}]}
return json.dumps(data),200,[('Content-Type'.'application/json; charset=utf-8')]
Copy the code
  • The set_cookie() function is provided in the Response class to set the Cookie of the client. To set the Cookie, we need to build the Response instance by ourselves (through make_response). Optional parameters are as follows:
Set_cookie (key, // key value=' ', // value max_age=None, // Cookie lifetime in seconds, None means HTTP-only expires=None, // Expiration time, datetime object or Unix timestamp PATH ='/'// Secure =None, httpOnly =False)Copy the code

Redirects and sessions

Redirects and sessions are often handled in Web development, and Flask has “Redirect” and “session” built in to handle them.

0 x1 redirection

In Flask, the redirect object is used to redirect the page to the login page. By default, the status code is 302, which can be modified by passing in the code parameter: 301,302,303,305 and 307, simple code examples are as follows:

# coding=utf-8
from flask import Flask, redirect

app = Flask(__name__)

user_name = ' '

@app.route('/article')
def article():
    if user_name == ' ':
        If the username is empty, redirect to the login page
        return redirect('/login')
    else:
        return "Article page"

@app.route("/login")
def login():
    global user_name
    user_name = 'admin'
    return "Login successful!"

if __name__ == "__main__":
    app.run(debug=True)
Copy the code

The operation process is as follows:

Browser type: automatically jump to: http://127.0.0.1:5000/article, http://127.0.0.1:5000/login, show the login successfully Again visit: http://127.0.0.1:5000/article, according to the article pageCopy the code

0 x2 session

We can store data in user sessions, which are private storage stored in client cookies by default. The session addresses two main issues: visitor identification and visitor information logging. When the browser accesses the server for the first time, the server sets a unique session ID in its cookie. The header of the browser’s subsequent access to the server will automatically contain this information. The server uses this ID number to distinguish different visitors. Flask provides session objects to operate user sessions. You can use the [] operator to read or set specified key values. By default, Flask encrypts session objects and stores them in client cookies. Therefore, an encryption seed must be configured on the application instance’s secret_key property to use sessions. Examples of usage are as follows:

# set the session
session['name'] = 'jay'
Read the session #
session.get('name')
# Configure the crypto seed (choose one of two methods)
app.secret_key = '123456' 
app.config['SECRET_KEY'] ='123456'
Copy the code

9, static file management

Static files are files that cannot be changed, such as images, CSS style files, JavaScript script files, font files, etc. Flask by default looks for static files in a subdirectory named Static in the root directory, so if you need static files you can create a static folder and drop them in there. Consider the following structure for organizing projects:

static/
    css/
        lib/
            bootstrap.css
        style.css
        home.css
    js/
        lib/
            jquery.js
            chart.js
        home.js
    img/
        logo.svg
        favicon.ico
Copy the code

Also, do not write static file paths dead in the template, instead use the url_for function to generate paths, as shown in the following example:

url_for('static', filename='css/style.css')
Copy the code

Of course, if you want to change the actual directory of a static file, you can pass in the Flask constructor parameter: static_folder=’ folder name ‘. In addition, in order to obtain better processing power, it is recommended to use Nginx or other Web servers to manage static files, images and other resources can be hosted on the CDN platform. (Such as Seven Niuyun)


10, blueprints,

Blueprint, which defines a collection of views, templates, static files, and so on that can be used by a single application. Commonly understood as a good tool to achieve application modularization, using blueprints can make the project level clearer, easier to develop and maintain, usually for routes with the same URL prefix. Let’s start with an example that doesn’t use blueprints:

# coding=utf-8
from flask import Flask

app = Flask(__name__)

@app.route('/user/index')
def user_index():
    return 'user_index'

@app.route('/user/show')
def user_show():
    return 'user_show'

@app.route('/user/add')
def user_add():
    return 'user_add'

@app.route('/admin/index')
def admin_index():
    return 'admin_index'

@app.route('/admin/show')
def admin_show():
    return 'admin_show'

@app.route('/admin/add')
def admin_add():
    return 'admin_add'

if __name__ == "__main__":
    app.run(debug=True)
    
Copy the code

The above code is pretty neat, but there are a few problems:

  • If user and admin had hundreds of functions instead of just a few, the code would be huge and bloated.
  • Large projects are collaborative, and dealing with merge conflicts can be a headache if everyone is working in a file.
  • If one day these two user modules do not need to find line by line, and then delete the code.

We used the blueprint to split user and admin into two different.py files. The admin.py file looks like this:

# coding=utf-8
from flask import Blueprint

admin = Blueprint('admin', __name__,url_prefix='/admin')

@admin.route('/index')
def admin_index():
    return 'admin_index'

@admin.route('/show')
def admin_show():
    return 'admin_show'

@admin.route('/add')
def admin_add():
    return 'admin_add'
Copy the code

The contents of the user.py file are as follows:

# coding=utf-8
from flask import Blueprint

user = Blueprint('user',__name__)

@user.route('/index')
def user_index():
    return 'user_index'

@user.route('/show')
def user_show():
    return 'user_show'

@user.route('/add')
def user_add():
    return 'user_add'
Copy the code

To register the blueprint, hello.py looks like this:

# coding=utf-8
from flask import Flask
from admin import *
from user import *

app = Flask(__name__)
app.register_blueprint(admin)
app.register_blueprint(user, url_prefix='/user')

if __name__ == "__main__":
    print(app.url_map)
    app.run(debug=True)
Copy the code

Use the app.url_map function to view all routes. The output is as follows:

Map([<Rule '/admin/index' (GET, HEAD, OPTIONS) -> admin.admin_index>,
 <Rule '/admin/show' (GET, HEAD, OPTIONS) -> admin.admin_show>,
 <Rule '/admin/add' (GET, HEAD, OPTIONS) -> admin.admin_add>,
 <Rule '/user/index' (GET, HEAD, OPTIONS) -> user.user_index>,
 <Rule '/user/show' (GET, HEAD, OPTIONS) -> user.user_show>,
 <Rule '/user/add' (GET, HEAD, OPTIONS) -> user.user_add>,
 <Rule '/static/<filename>' (GET, HEAD, OPTIONS) -> static>])
Copy the code

The url_prefix parameter is used to set the URL prefix in request.url, and only requests that meet the prefix will be processed and returned through the view method of the registered blueprint. It can be written in a submodule or passed in at register_blueprint registration time, just once! After open the http://127.0.0.1:5000/admin/index, you can see As shown in the results:


G objects and hook functions

Sometimes it is useful to execute specific code before and after a request is processed. This uses request hooks, for example: Flask provides the function of registering general functions, just need to write a request hook — function, the whole application instance is applied globally, such as the example of verifying user status before request, jump to login page before login, etc. The hook function uses Flask’s global variable G as an intermediate variable to pass data between the hook function and the view function.

0 x1 g object

The G, global, and G objects are used to store user data, which can be used globally. A code example is as follows:

from flask import g, request

@app.route('/')
def index():
    user = request.args.get('user')
    g.user = user   Save user data
Copy the code

0x2 Hook function

Flask provides the following four hook functions:

  • Before_first_request: called before the first request, you can do some initialization in this method.
  • Before_request: called before each request. Check is performed. If the check is not successful, you can respond directly in this method.
  • After_request: called after executing a view function and passing in the response generated by the view function, where the response can be processed in the last step of approval.
  • Teardown_request: this is called after each request and receives an error message from the server.

Write a program to verify the execution of the hook function (after running, call it twice) :

127.0.0.1 -- -- [30/Aug/2018 10:53:42]"The GET/HTTP / 1.1" 200 -
before_first_request
before_request
after_request
teardown_request

127.0.0.1 - - [30/Aug/2018 10:53:45] "The GET/HTTP / 1.1" 200 -
before_request
after_request
teardown_request
Copy the code

11. Context

A context is a container that holds some information during the operation of the Flask program, which is divided into two types according to the management mechanism:

  • RequestContext: A Request object that encapsulates the content of an Http Request. Session: Reloads the Session information associated with the visitor based on the cookie in the request.

  • Program context (AppContext) G: processing requests as a temporary storage object, save is the global variable of the current request, different requests will have different global variables! Current_app: An instance of a currently running program that holds the variables of the application. For example, you can use current_app.name to obtain the name of the current application. You can also store configuration information, variables, and so on in current_app. Current_app. Text = ‘value’.

Flask, and the context management can be divided into three stages:

  • When the request comes in: encapsulate the request and session in the RequestContext class, app and G in the AppContext class, and use the LocalStack to place the RequestContext and AppContext in the Local class.
  • View function: Choose LocalProxy > partial function > localStack > local.
  • Before the request ends: execute save.session() -> execute pop() respectively -> clear data in local.

12. Exception handling

The abort() function is used to abort an exception that is not intended to be displayed to the user, or the same processing is needed. The most common example of this code is 404.

@app.route("/test")
def test():
abort(404)

@app.errorhandler(404)
def error(e):
    return "A nice 404 page."
Copy the code

After code execution, browser type: http://127.0.0.1:5000/test, you can see as shown in the results:

Alternatively, you can write all exception handling into a blueprint as shown in the following code:

# coding=utf-8
from flask import Blueprint, abort

exception = Blueprint('exception', __name__)

@exception.errorhandler(404)
def error(e):
    return "A nice 404 page."

# Registration Blueprint
from error import exception
app.register_blueprint(exception, url_prefix='/error')
Copy the code

ORM Framework — SQLAlchemy

Use the Object-Relational Mapper ORM framework to manipulate databases. The ORM framework is:

“Abstraction of low-level data manipulation instructions into high-level object-oriented operations”

Instead of writing tedious SQL operations, the ORM framework simplifies operations on Python objects.

Tables map to classes, rows as instances, and fields as attributes.

ORM converts object operations into database native statements when they are performed. The most widely used ORM framework for Python is SQLAlchemy.

0 x1 flask – sqlalchemy installation

Install using the PIP command

pip install flask-sqlalchemy
Copy the code

In addition, SQLAlchemy cannot operate the database itself. It relies on pymysql and other third-party libraries. There is a Dialect module in the Dialect module that is specifically used to communicate with the data API, and call different database apis based on the configuration files. Common database engines and their corresponding urls are shown in the following table:

Database engine URL
MySQL mysql+pymysql://username:password@hostname/database
Postgres postgresql://username:password@hostname/database
SQLite(Unix, leading four slashes) sqlite:////absolute/path/to/database
SQLite (Windows) sqlite:///c:/absolute/path/to/database
Postgres postgresql://username:password@hostname/database
Oracle oracle://username:password@hostname/database

Brief description of parameters:

  • Username: indicates the username for logging in to the database.
  • Password: indicates the password for logging in to the database.
  • Hostname: The main clause where the SQL service resides, either locally or remotely.
  • Database: indicates the database used.

0x2 Connecting to a Database

Example code for connecting to a MySQL database is as follows:

from sqlalchemy import create_engine

engine = create_engine('mysql+pymysql://jay:zpj12345@localhost:3306/todo')
with engine.connect() as con:
    rs = con.execute("SELECT 1")
    print(rs.fetchone())
Copy the code

The following output is displayed:

(1)Copy the code

You can also initialize SQLAlchemy by using the following code example:

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
app = Flask(__name__)
    db.init_app(app)
Copy the code

0x3 Uses native SQL

Sqlalchemy supports direct execution of native SQL statements, as shown in the following code example:

from sqlalchemy import create_engine

engine = create_engine('mysql+pymysql://jay:zpj12345@localhost:3306/todo')
with engine.connect() as con:
    con.execute("CREATE TABLE IF Not Exists note(_id INT AUTO_INCREMENT PRIMARY KEY, tran TEXT, status int)")
    con.execute("INSERT INTO note(tran, status) VALUES (' 1 ', 1))
    con.execute("INSERT INTO note(tran, status) VALUES (' sleep ', 1)")
    rs = con.execute("SELECT * FROM note")
    for row in rs:
        print(row)
Copy the code

The code output is as follows:

(1, 'eat', 1)
(2, 'sleep'1),Copy the code

0x4 ORM Model and basic operations

To demonstrate the basic operations of flask-SQLAlchemy in a wave:

  • Create table create_all drop_all
# models.py
from manager import db

class Note(db.Model):
    __tablename__ = 'note'
    _id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
    tran = db.Column(db.TEXT)
    status = db.Column(db.INT,default=0)

db.create_all() # to create table
Copy the code
  • 2. Insert data
from model import Note
from manager import db

def create_note():
    Create a new object
    note1 = Note()
    note1.tran = "Eat"
    note1.status = "1"

    note2 = Note()
    note2.tran = "Sleep"
    note2.status = "2"

    Add new note to database session
    db.session.add(note1)
    db.session.add(note2)

    # commit database session changes to the database. If you do not commit, the database content will not change
    db.session.commit()

create_note()
Copy the code
  • 3. Delete data
def delete_note():
    Select * from * where id=1;
    note = Note.query.filter_by(_id=1).first()

    # Delete notes
    db.session.delete(note)

    Commit database session
    db.session.commit()

delete_note()
Copy the code
  • 4. Modify data
def update_note():
    Select * from * where id=2;
    note = Note.query.filter_by(_id=2).first()

    # Modify notes
    note.tran = "Beat the beans."

    Commit database session
    db.session.commit()

update_note()
Copy the code
  • 5. Query data

When it comes to queries, there must be query conditions, and SQLAlchemy provides common query functions as shown in the following table:

function describe Use the sample
filter_by Precise query filter_by(xxx=’xxx’)
filter Fuzzy query filter(xxx.endWith(‘xxx’))
get(primary key) The value is usually id get(1)
not_(a) == ==! = not_(xxx=’xxx’)
and_(a) Logic and and_(xxx=’xxx’)
or_(a) Logic or or_(xxx=’xxx’)
in_(a) In a certain range XXX, XXX. In_ ((1, 2, 3))
notin_(a) Not in a certain range XXX, XXX. Notin_ ((1, 2, 3))
first(a) Returns an object from the query XXX.query.first()
all(a) Returns all queried objects XXX.query.all()
order_by(a) The sorting XXX.order_by(xxx.xxx.desc())
limit(a) Limit the number of returns XXX.limit(3)
offset(a) Set offset XXX.offset()
count(a) Returns the total number of records xxx.count()

A code example is as follows:

from sqlalchemy import not_, or_

def query_all():
    notes = Note.query.all()
    print("Query all data:", notes)
    note = Note.query.filter(not_(or_(Note.tran == 'eat', Note.tran == 'sleep'))).first()
    print(note._id, ":", note.tran, ":", note.status)

if __name__ == '__main__':
    Insert some data first
    create_note()
    create_note()
    query_all()
Copy the code

The following output is displayed:

Query all data: [<Note 2>, <Note 3>, <Note 4>, <Note 5>, <Note 6>Copy the code

14.Web forms plugin — Flask-wtf

Flask-wtf extensions, which simply inherit WTForms, include CSRF (Cross-domain Request Forgeries), the ability to validate form data, file uploads, and Google embedded captchas.

0x1 Standard HTML field supported by WTForms

The field type instructions
StringField The text field
TextAreaField Multi-line text field
PasswordField Password text field
HiddenField Hide text field
DateField A text field with a value in datetime.date format
DateTimeField A text field with a datetime.datetime format
IntegerField A text field with an integer value
DecimalField A text field with a value of decimal.decimal
FloatField A text field with a floating point value
BooleanField Check box with values True and False
RadioField A set of single boxes
SelectField The drop-down list
SelectMultipleField You can select multiple values from a drop-down list
FileField File upload field
SubmitField Form Submission button
FormField Embed a form as a field in another form
FieldList A set of fields of a specified type

0x2 WTForms validates the function

Validation functions instructions
Email Verify the email address
EqualTo Compare the values of two fields, often used when you need to enter a password twice for confirmation
IPAddress Verify the IPv4 network address
Length Validates the length of the input string
NumberRange Verify that the entered value is in the numeric range
Optional Skip other validation functions if there is no input value
Required Make sure there is data in the field
Regexp Use regular expressions to validate input values
URL Verify the URL
AnyOf Make sure the input value is in the list of optional values
NoneOf Make sure the input value is not in the optional list

0x3 Write a simple example

Let’s write an example of a registration form:

# coding=utf-8
from flask import Flask, request, render_template
from flask_wtf import FlaskForm
Import the fields required by the custom form
from wtforms import SubmitField, StringField, PasswordField
Import form validation
from wtforms.validators import DataRequired, EqualTo

app = Flask(__name__)
app.config['SECRET_KEY'] = '123456'


# Custom form classes
# StringField and PasswordField are used to distinguish text box types
The first argument is the label value, and the second argument validators is the content to validate
class RegisterForm(FlaskForm):
    username = StringField('Username :', validators=[DataRequired()])
    password = PasswordField('password:, validators=[DataRequired()])
    password2 = PasswordField('Confirm password :', validators=[DataRequired(), EqualTo('password'.'Two different passwords entered! ')])
    submit = SubmitField('registered')


@app.route("/register", methods=['GET'.'POST'])
def register():
    Instantiate the registration form class
    register_from = RegisterForm()
    if request.method == 'POST':
        Get request parameters
        username = request.form.get('username')
        password = request.form.get('password')
        password2 = request.form.get('password2')
        Call validation_on_submit to execute all the logic of the validation function at once
        if register_from.validate_on_submit():
            return 'Registration successful! '
        else:
            return 'Inconsistent passwords! '
    return render_template('register.html', form=register_from)


if __name__ == "__main__":
    print(app.url_map)
    app.run(debug=True)

Copy the code
# templates/register.html<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="post">
        {Scrf_token #}{{ form.csrf_token() }} {{ form.username.label }}&nbsp; &nbsp; {{ form.username }}<br> {{ form.password.label }}&nbsp; &nbsp; {{ form.password }}<br> {{ form.password2.label }}&nbsp; &nbsp; {{ form.password2 }}<br> <br> {{ form.submit }} </form> </body> </html>Copy the code

Enter a wave of the same password and a wave of different passwords, and the browser will output something like this:

One other thing to note:

Flask-wtf requires configuration of the SECRET_KEY parameter, CSRF_ENABLED for **CSRF (cross-site request forgery) ** protection. SECRET_KEY is used to generate encryption tokens based on the set key when CSRF is activated.


15. A simple generic Flask project structure

Flask is done with the basics. Then we standardize the project structure. A simple and general project structure is shown here:

A brief description of the structure:

  • App: Package directory for the entire project.
  • Models: Data model.
  • Static: static files, CSS, JavaScript, ICONS, etc.
  • Templates: template file.
  • Views: view file.
  • Config. py: indicates the configuration file.
  • Venv: Virtual environment.
  • Manage.py: project startup control file.
  • Requirements. TXT: project startup control file.

Create process:

Initialize the app instance in __init__.py as follows:

from flask import Flask

app = Flask(__name__)
Copy the code

Write a simple index route in views.py:

from app import app
from flask import render_template

@app.route('/')
def index():
    return render_template("index.html")
Copy the code

The templates folder creates an index.html:

<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Hello Flask! </h1> </body> </html>Copy the code

Next type: Python manage.py runserver, open your browser: http://127.0.0.1:5000/

The project structure is basically done, and then we dump the project onto the remote server.


16. Deploy the Flask project to the cloud server

0x1 Code is uploaded to the cloud server

There are two alternative methods. The simplest method is to use the FTP/SFTP tool to upload the file directly. Another method is to host the project on a code hosting platform such as Github, and then directly SSH to the cloud server and copy the project to the server through git clone command. Here, the author directly uses the first method to upload the project to the cloud server.

Install nginx 0 x2

Nginx is a lightweight, strong performance, less resource, can handle high concurrency reverse proxy software. Flask: The Flask Web Server can only be installed by a single thread. The Flask Web Server can only be installed by a single thread. The Flask Web Server can only be installed by a single thread.

apt-get install nginx
Copy the code

After the installation, if the external network accesses the public IP address of the server, the installation is successful if the following page is displayed:

After Nginx is installed, the default directory will be created: /var/www/. We will move our project directly to this directory by command.

mv AutoPubNews /var/www/AutoPubNews
Copy the code

0x3 Installing and Configuring uWSGi

WSGI is a WEB server, or gateway interface, a specification (protocol) for WEB servers (such as NGINx) to communicate with application servers (such as uWSGI). UWSGI implements all the interfaces of WSGI and is a fast, self-healing, developer – and system-administration-friendly server. UWSGI code is written entirely in C with high efficiency and stable performance. For example, uWSGI converts the HTTP protocol to the WSGI protocol, which Python can use directly. Install by typing PIP command directly:

pip install uwsgi
Copy the code

Libpython3. X -dev: libpython3. X -dev: libpython3.

Apt to get the install libpython3.5 - devCopy the code

To configure uWSGi, create a config. Ini file in the project:

vim config.ini
Copy the code

Add the following:

[uwsgi]
# address and port used for uWSGi startupThe socket = 127.0.0.1:8001You can use other ports

# point to the site directory
chdir = /var/www/AutoPubNews                                                                   

# Python startup file
wsgi-file = manage.py                                                                      

The name of the application variable used to start a Python program
callable = app                                                                              

# number of processors
processes = 4                                                                               

# threads
threads = 2                                                                                 

State check addressStats = 127.0.0.1:5000Copy the code

Then execute the following command:

uwsgi config.ini
Copy the code

If the following command output is displayed: Stats Server Enabled on 127.0.0.1:5000, the server is normally started.

0 x4 Nginx configuration

/etc/nginx/sites-available/default: /etc/nginx/sites-available/default: /etc/nginx/sites-available/default: /etc/nginx/sites-available/default: /etc/nginx/sites-available/default: /etc/nginx/sites-available/default: /etc/nginx/sites-available/default

server {
      listen  80;
      server_name _; 

      location / {
        include      uwsgi_params;
        uwsgi_pass   127.0.0.1:8001;  # point to the internal address applied by UWSGi. All requests are forwarded to UWSGi for processing
        uwsgi_param UWSGI_PYHOME /home/www/AutoPubNews/venv; Point to the virtual environment directory
        uwsgi_param UWSGI_CHDIR  /home/www/AutoPubNews; # point to the site root directory
        uwsgi_param UWSGI_SCRIPT manager:app; #  }}Copy the code

Then type the following command to restart the loaded nginx configuration:

sudo service nginx restart
Copy the code

Then start uWSGi and you can access our project directly from the server’s public IP:

0x5 Domain Name Resolution

It seems a little tedious to use IP for each project visit. We can buy a domain name to do the mapping. Domain name directly buy good, need to put on record, after fixing open domain name management page, find just bought domain name click resolution

Then click “Add Record” and the dialog box as shown in the picture will appear. You can fill in the public IP address of your cloud server where the record value is.

At this point, you can access our project directly through the domain name.


Well, that’s it for Flask quick. Next we’ll write apis, dynamically generate pages, and so on. If you have any questions, please leave them in the comments section. Thank you

Tips: public at present just adhere to the morning post, slowly improve, a little guilty, only dare to post a small picture, want to see the morning post can pay attention to ~