跳转至

26 python web

Python Web 开发⚓︎

Python 是一种通用编程语言,可以用于很多场景。本节我们看看如何用 Python 做 Web。Python 有许多 Web 框架,其中 Django 和 Flask 最流行。今天我们学习如何用 Flask 做 Web 开发。

Flask⚓︎

Flask 是用 Python 编写的 Web 开发框架。Flask 使用 Jinja2 模板引擎,也可以与 React 等现代前端库一起使用。

如果还没有安装 virtualenv,请先安装。虚拟环境可以把项目依赖与本机依赖隔离开。

文件夹结构⚓︎

完成所有步骤后,项目文件结构应如下所示:

├── Procfile
├── app.py
├── env
│   ├── bin
├── requirements.txt
├── static
│   └── css
│       └── main.css
└── templates
    ├── about.html
    ├── home.html
    ├── layout.html
    ├── post.html
    └── result.html

搭建项目目录⚓︎

按下面的步骤开始使用 Flask。

步骤 1:用下面的命令安装 virtualenv。

pip install virtualenv

步骤 2:

asabeneh@Asabeneh:~/Desktop$ mkdir python_for_web
asabeneh@Asabeneh:~/Desktop$ cd python_for_web/
asabeneh@Asabeneh:~/Desktop/python_for_web$ virtualenv venv
asabeneh@Asabeneh:~/Desktop/python_for_web$ source venv/bin/activate
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip install Flask
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$

我们创建了一个名为 python_for_web 的项目目录。在项目中创建了虚拟环境 venv(名字可以随便起,我习惯叫 venv)。然后激活了虚拟环境。用 pip freeze 检查项目目录中已安装的包。由于尚未安装任何包,pip freeze 的结果为空。

现在,在项目目录中创建 app.py 并写入下面的代码。app.py 将是项目的主文件。下面的代码用到了 flask 模块和 os 模块。

创建路由⚓︎

首页路由。

# let's import the flask
from flask import Flask
import os # importing operating system module

app = Flask(__name__)

@app.route('/') # this decorator create the home route
def home ():
    return '<h1>Welcome</h1>'

if __name__ == '__main__':
    # for deployment we use the environ
    # to make it work for both production and development
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

要运行 Flask 应用,在 Flask 应用主目录下执行 python app.py

运行 python app.py 后,在本地访问 5000 端口进行检查。

我们再增加一条路由。 创建 about 路由:

# let's import the flask
from flask import Flask
import os # importing operating system module

app = Flask(__name__)

@app.route('/') # this decorator create the home route
def home ():
    return '<h1>Welcome</h1>'

@app.route('/about')
def about():
    return '<h1>About us</h1>'

if __name__ == '__main__':
    # for deployment we use the environ
    # to make it work for both production and development
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

上面我们已经加入了 about 路由。如果想渲染 HTML 文件而不是字符串呢?可以使用 render_template 函数渲染 HTML。在项目目录中创建名为 templates 的文件夹,并创建 home.htmlabout.html。同时从 flask 导入 render_template 函数。

创建模板⚓︎

在 templates 文件夹中创建 HTML 文件。

home.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Home</title>
  </head>

  <body>
    <h1>Welcome Home</h1>
  </body>
</html>

about.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>About</title>
  </head>

  <body>
    <h1>About Us</h1>
  </body>
</html>

Python 脚本⚓︎

app.py

# let's import the flask
from flask import Flask, render_template
import os # importing operating system module

app = Flask(__name__)

@app.route('/') # this decorator create the home route
def home ():
    return render_template('home.html')

@app.route('/about')
def about():
    return render_template('about.html')

if __name__ == '__main__':
    # for deployment we use the environ
    # to make it work for both production and development
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

可以看出,要访问不同页面或做导航,需要导航链接。我们给每个页面加一个链接,或者创建一个所有页面共用的布局。

导航⚓︎

<ul>
  <li><a href="/">Home</a></li>
  <li><a href="/about">About</a></li>
</ul>

现在可以用上面的链接在页面间导航。我们再创建一个处理表单数据的页面,名字随意,我喜欢叫 post.html

我们可以用 Jinja2 模板引擎向 HTML 文件注入数据。

# let's import the flask
from flask import Flask, render_template, request, redirect, url_for
import os # importing operating system module

app = Flask(__name__)

@app.route('/') # this decorator create the home route
def home ():
    techs = ['HTML', 'CSS', 'Flask', 'Python']
    name = '30 Days Of Python Programming'
    return render_template('home.html', techs=techs, name = name, title = 'Home')

@app.route('/about')
def about():
    name = '30 Days Of Python Programming'
    return render_template('about.html', name = name, title = 'About Us')

@app.route('/post')
def post():
    name = 'Text Analyzer'
    return render_template('post.html', name = name, title = name)


if __name__ == '__main__':
    # for deployment
    # to make it work for both production and development
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

再看看模板:

home.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Home</title>
  </head>

  <body>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
    <h1>Welcome to {{name}}</h1>
     <ul>
    {% for tech in techs %}
      <li>{{tech}}</li>
    {% endfor %}
    </ul>
  </body>
</html>

about.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>About Us</title>
  </head>

  <body>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
    <h1>About Us</h1>
    <h2>{{name}}</h2>
  </body>
</html>

创建布局⚓︎

模板文件里有很多重复代码,可以写一个布局来消除重复。在 templates 文件夹中创建 layout.html。 创建布局后,会在每个文件中引入它。

提供静态文件⚓︎

在项目目录中创建 static 文件夹。在 static 中创建 CSS 或 styles 文件夹,并创建 CSS 样式表。我们使用 url_for 来提供静态文件。

layout.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://fonts.googleapis.com/css?family=Lato:300,400|Nunito:300,400|Raleway:300,400,500&display=swap"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="{{ url_for('static', filename='css/main.css') }}"
    />
    {% if title %}
    <title>30 Days of Python - {{ title}}</title>
    {% else %}
    <title>30 Days of Python</title>
    {% endif %}
  </head>

  <body>
    <header>
      <div class="menu-container">
        <div>
          <a class="brand-name nav-link" href="/">30DaysOfPython</a>
        </div>
        <ul class="nav-lists">
          <li class="nav-list">
            <a class="nav-link active" href="{{ url_for('home') }}">Home</a>
          </li>
          <li class="nav-list">
            <a class="nav-link active" href="{{ url_for('about') }}">About</a>
          </li>
          <li class="nav-list">
            <a class="nav-link active" href="{{ url_for('post') }}"
              >Text Analyzer</a
            >
          </li>
        </ul>
      </div>
    </header>
    <main>
      {% block content %} {% endblock %}
    </main>
  </body>
</html>

现在,去掉其他模板文件中的重复代码,并引入 layout.html。导航的 href 使用 url_for 函数,传入路由函数名来连接各个导航路由。

home.html

{% extends 'layout.html' %} {% block content %}
<div class="container">
  <h1>Welcome to {{name}}</h1>
  <p>
    This application clean texts and analyse the number of word, characters and
    most frequent words in the text. Check it out by click text analyzer at the
    menu. You need the following technologies to build this web application:
  </p>
  <ul class="tech-lists">
    {% for tech in techs %}
    <li class="tech">{{tech}}</li>

    {% endfor %}
  </ul>
</div>

{% endblock %}

about.html

{% extends 'layout.html' %} {% block content %}
<div class="container">
  <h1>About {{name}}</h1>
  <p>
    This is a 30 days of python programming challenge. If you have been coding
    this far, you are awesome. Congratulations for the job well done!
  </p>
</div>
{% endblock %}

post.html

{% extends 'layout.html' %} {% block content %}
<div class="container">
  <h1>Text Analyzer</h1>
  <form action="https://thirtydaysofpython-v1.herokuapp.com/post" method="POST">
    <div>
      <textarea rows="25" name="content" autofocus></textarea>
    </div>
    <div>
      <input type="submit" class="btn" value="Process Text" />
    </div>
  </form>
</div>

{% endblock %}

请求方法有多种(GET、POST、PUT、DELETE),它们是常见的请求方法,允许我们做 CRUD(Create、Read、Update、Delete)操作。

在 post 路由中,我们会根据请求类型交替使用 GET 和 POST 方法,请看下面代码中的写法。request 方法用于处理请求方法,也可以用来访问表单数据。 app.py

# let's import the flask
from flask import Flask, render_template, request, redirect, url_for
import os # importing operating system module

app = Flask(__name__)
# to stop caching static file
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0



@app.route('/') # this decorator create the home route
def home ():
    techs = ['HTML', 'CSS', 'Flask', 'Python']
    name = '30 Days Of Python Programming'
    return render_template('home.html', techs=techs, name = name, title = 'Home')

@app.route('/about')
def about():
    name = '30 Days Of Python Programming'
    return render_template('about.html', name = name, title = 'About Us')

@app.route('/result')
def result():
    return render_template('result.html')

@app.route('/post', methods= ['GET','POST'])
def post():
    name = 'Text Analyzer'
    if request.method == 'GET':
         return render_template('post.html', name = name, title = name)
    if request.method =='POST':
        content = request.form['content']
        print(content)
        return redirect(url_for('result'))

if __name__ == '__main__':
    # for deployment
    # to make it work for both production and development
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

目前我们已经看过如何使用模板、如何向模板注入数据、以及如何使用公共布局。 接下来处理静态文件。在项目目录中创建名为 static 的文件夹,再创建名为 css 的文件夹。在 css 文件夹中创建 main.css。你的 main.css 将链接到 layout.html

CSS 文件不必自己写,复制使用即可。接下来进入部署。

部署⚓︎

创建 Heroku 账号⚓︎

Heroku 为前端和全栈应用提供免费部署服务。在 heroku 创建账号,并为你的机器安装 heroku CLI。 安装完成后运行下面的命令。

登录 Heroku⚓︎

asabeneh@Asabeneh:~$ heroku login
heroku: Press any key to open up the browser to login or q to exit:

从键盘任意按键,查看结果。按任意键后会打开 Heroku 登录页面,点击登录。然后本机就会连接到远程 Heroku 服务器。若已连接到远程服务器,你会看到:

asabeneh@Asabeneh:~$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/browser/be12987c-583a-4458-a2c2-ba2ce7f41610
Logging in... done
Logged in as asabeneh@gmail.com
asabeneh@Asabeneh:~$

创建 requirements 和 Procfile⚓︎

在把代码推送到远程服务器之前,我们需要:

  • requirements.txt
  • Procfile
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch requirements.txt
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze > requirements.txt
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ cat requirements.txt
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch Procfile
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ ls
Procfile          env/              static/
app.py            requirements.txt  templates/
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$

Procfile 中将包含在 Web 服务器(本例中为 Heroku)上运行应用的命令。

web: python app.py

将项目推送到 Heroku⚓︎

现在可以部署了。在 Heroku 上部署应用的步骤:

  1. git init
  2. git add .
  3. git commit -m "commit message"
  4. heroku create 'name of the app as one word'
  5. git push heroku master
  6. heroku open(启动已部署的应用)

完成这些步骤后,你会得到类似 这个 的应用。

练习:第 26 天⚓︎

  1. 你将构建 这个应用。只剩文本分析器部分待完成。