1.前提准备
-
Python
版本# python 3.8.0 # 查看Python版本 python --version
-
安装第三方
Flask
pip install flask # 如果安装失败,可以使用 -i,指定使用国内镜像源 # 清华镜像源:https://pypi.tuna.tsinghua.edu.cn/simple/
-
检查
Flask
是否安装成功flask --version
-
Flask官网
# 官网:https://flask.palletsprojects.com # 快速开始:https://flask.palletsprojects.com/en/3.0.x/quickstart/
2.一个简单的Flask程序
-
创建
Flask
项目目录。mkdir FlaskMarket
-
创建
app
文件。from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
-
运行
Flask
。flask --app market run
# 设置环境变量,也能够直接运行flask $env:FLASK_APP="market.py" flask run
查看web页面
Debug 模式
# 运行flask项目时,在最后加--debug,以debug模式启动 $env:FLASK_APP="market.py" flask run --debug
以下是代码产生报错的截图
-
新增一个路由。
# 路由传参username @app.route("/about/<username>") def about_page(username): return f"<h1>this is about {username} page</h1>"
页面查询结果
3.Template模板文件
可以在Flask项目的目录下创建 templates
目录存放所会用的 html
文件,具体如下:
在Python代码中,直接返回 html
文件即可,不需要携带目录。
@app.route("/")
def hello_world():
return render_template("hello.html")
页面访问如下
4.数据发送到template
Jinjia2
是一个仿照 Django
模板的 Python
模板语句,实现了后端与模板之间的交互。
-
一个简单的数据交互。
后端
python
这样写:@app.route("/") def hello_world(): return render_template("home.html", item_name="Phone")
对应的前端
html
文件需要使用jiajia2
的语法接收变量,代码如下:<p>{{item_name}}</p>
页面效果如下:
-
列表数据交互。
后端
python
这样写:@app.route("/") def hello_world(): items = [ {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500}, {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500}, {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150}, ] return render_template("home.html", items=items)
对应的前端
html
这样接收:<table class="table table-hover table-dark"> <thead> <tr> <th scope="col">ID</th> <th scope="col">Name</th> <th scope="col">Barcode</th> <th scope="col">Price</th> </tr> </thead> <tbody> {% for item in items %} <tr> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.barcode}}</td> <td>{{item.price}}</td> </tr> {% endfor %} </tbody> </table>
访问页面如下:
5.Template 继承
开发的网站可能涉及多个页面,需要抽取公共的内容,其余的 html
页面继承这些公共内容即可。
-
引入
base.html
文件。<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> <title>Base Title</title> </head> <body> <!-- Navbar here --> <nav class="navbar navbar-expand-md navbar-dark bg-dark"> <a class="navbar-brand" href="#">EuanSu Coding Market</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="*navbarNav"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav mr-auto"> <li class="nav-item active"> <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="#">Market</a> </li> </ul> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="#">Login</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Register</a> </li> </ul> </div> </nav> <!-- Future Content here --> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src='https://kit.fontawesome.com/a076d05399.js'></script> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script> </body> <style> body { background-color: #212121; color: white } </style> </html>
-
清空
home.html
原文件,修改为如下内容:{% extends "base.html" %}
-
访问页面如下:
这里有一个问题就是页面标题显示为
Base Title
,实际上每个页面的标题是不一样,这里可以通过block
语句进行修改,代码如下:修改
base.html
文件head
下的title
标签为如下内容:<head> ... <title> {% block title%} {% endblock %} </title> </head>
修改
home.html
为如下内容:{% extends "base.html" %} {% block title%} Home Page {% endblock %}
再次刷新页面,
title
的内容被替换。 -
替换
html
文件body
下的内容:首先是修改
base.html
中body
的内容,修改如下:{% block content%} {% endblock %}
修改
market.html
为如下内容:{% extends "base.html" %} {% block title%} Market Page {% endblock %} {% block content%} <table class="table table-hover table-dark"> <thead> <tr> <th scope="col">ID</th> <th scope="col">Name</th> <th scope="col">Barcode</th> <th scope="col">Price</th> </tr> </thead> <tbody> {% for item in items %} <tr> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.barcode}}</td> <td>{{item.price}}</td> <td> <button class="btn btn-outline btn-info">More Info</button> <button class="btn btn-outline btn-success">Purchase this Item</button> </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
访问页面,能够正常对数据进行渲染。
-
页面跳转
html
文件的href
进行跳转,这里需要使用jinjia2
的语法,而不能直接使用路由。<a class="nav-link" href="{{ url_for('home_page') }}">Home <span class="sr-only">(current)</span></a> <a class="nav-link" href="{{ url_for('market_page') }}">Market</a>
其中的
market_page
是路由关联的函数,如下所示:@app.route("/") def home_page(): items = [ {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500}, {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500}, {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150}, ] return render_template("home.html", items=items) @app.route("/market") def market_page(): items = [ {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500}, {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500}, {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150}, ] return render_template("market.html", items=items)
再次点击页面的按钮,能够正常进行路由跳转。
6.数据库模型
6.1 数据库模型的基本使用
安装 flask-sqlalchemy
第三方包。
pip install flask-sqlalchemy
python
文件导入 flask-sqlalchemy
库。
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///market.sqlite'
db = SQLAlchemy(app)
编写模型类。
class Item(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(length=30),nullable=False, unique=True)
price = db.Column(db.Integer(), nullable=True)
barcode = db.Column(db.String(length=12), nullable=True, unique=True)
description = db.Column(db.String(length=1024), nullable=True, unique=True)
需要在 Flask
的 app
文件中,添加数据库初始化操作。
with app.app_context():
db.create_all()
使用可视化工具查看 SQLite
本地数据库文件,出现初始化的 Item
表。
6.2 SQLAlchemy 的基本使用
新增数据库记录
item1 = Item(name="OPPO Find X6 Pro",price=5000,barcode='123456789',description='OPPO Find X6 Pro')
with app.app_context():
db.session.add(item1)
db.session.commit()
执行如上语句后,数据库中出现一条手机记录。
查询数据库记录
# 全量查询
result = Item.query.all()
print(result)
for item in result:
print(item.name)
# 根据条件过滤
result = Item.query.filter_by(name='OPPO Find X6 Pro')
print(result)
print('=============')
for item in result:
print(item.name)
修改数据库记录
result = Item.query.filter_by(name='OPPO Find X6 Pro')
if result:
item = result[0]
item.price = 5999
db.session.commit()
修改后,数据库中的记录发生了变化。
删除数据库记录
# 查询要删除的记录
record_to_delete = Item.query.filter_by(name="OnePlus 12").first()
# 如果记录存在,则删除
if record_to_delete:
db.session.delete(record_to_delete)
db.session.commit()
这里的数据库查询放到代码中,如下:
@app.route("/market")
def market_page():
items = [
{"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
{"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
{"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
]
items = Item.query.all()
return render_template("market.html", items=items)
页面就能够直接展示数据库中的记录
7.项目重构
# 这里将项目移动至mark目录下,主目录下仅留项目的启动文件 run.py D:\CODE\PYTHON\FLASKMARKET ├─instance ├─market │ ├─templates │ │ ├─css │ │ ├─js │ │ ├─base.html │ │ ├─home.html │ │ └─market.html │ ├─__init__.py │ ├─models.py │ ├─routes.py │ └─__pycache__ ├─run.py └─__pycache__
修改后的各文件一次如下所示:
__init__.py
模块初始化文件:
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///market.sqlite'
db = SQLAlchemy(app)
from market import routes
models.py
模型文件:
from market import db
class Item(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(length=30),nullable=False, unique=True)
price = db.Column(db.Integer(), nullable=True)
barcode = db.Column(db.String(length=12), nullable=True, unique=True)
description = db.Column(db.String(length=1024), nullable=True, unique=True)
routes.py
路由文件:
from market import app
from flask import render_template
from market.models import Item
@app.route("/")
@app.route("/home")
def home_page():
items = [
{"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
{"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
{"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
]
return render_template("home.html", items=items)
@app.route("/market")
def market_page():
items = [
{"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
{"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
{"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
]
items = Item.query.all()
return render_template("market.html", items=items)
再次启动项目:
页面能够正常访问