第一个Flask项目
创建后项目如下图
static存放静态文件,templates存放Jinja2模板,app.py是整个项目的入口文件
我们略微理解下app.py这里的代码
# 从flask这个包中导入Flask类from flask import Flask#使用Flask类创建一个app对象#__name__:代表当前这个app.py模板#1.以后出现bug,可以帮助我们快速定位#2.对于寻找模板文件,有一个相对路径app = Flask(__name__)#创建一个路由和视图函数的映射#https://www.baidu.com#/home/user/。。。。#这里单独一个/表示根路由@app.route('/')def hello_world():# put application's code herereturn 'Hello World!'if __name__ == '__main__':app.run()
我们运行代码
进入网站查看
debug、host和port的配置
说明:
debug模式
- 开启debug模式后,只要修改代码后保存,就会自动重新加载,不需要手动重启项目
- 如果开发的时候,出现bug,如果开启了debug模式,在浏览器上就可以看到出错信息
修改host
- 主要作用:就是让其他电脑(包括任何可以联网的电子设备,比如手机,平板)能访问到我电脑上的flask项目
修改端口号
- 主要作用:如果5000端口被其他程序占用了,那么可以通过修改port来监听的端口号
URL与视图的映射
无参url
from flask import Flaskapp = Flask(__name__)# url:http[80]/https[443]//www.baidu.com:443/path#url与视图:其实可以理解为path与视图@app.route('/')def hello_world(): return 'Hello World!'@app.route('/demo')def china(): return 'Hello 中国'if __name__ == '__main__':app.run()
注意修改两个地方,一个是路径名,一个是函数名
有参url
带参数的url,将参数固定到了path中
@app.route('/demo2/')def demo2(id):return '您携带的id是%s' % id
如果去掉int:
,则传入什么都行,加入后只能传入int
类型,否则会报错
查询字符串的方式传参
用这种方式需要用到request,先在开头引入
from flask import Flask,request
#/book/list:会给我返回第一页的数据#/book/list" />@app.route('/book/list')def book_list():#arguments:参数#request.args:类字典类型page = request.args.get("page",default=1,type=int)return f"你得到的是第{page}的信息"
Jinja2
模板渲染
现在template里新建html文件
在body里填入内容就可以显示在页面上
比如在body里写个你好,运行代码
那么我们如何把页面渲染给前端,用render_template
from flask import Flask,render_templateapp = Flask(__name__)@app.route('/')def hello_world():# put application's code here# return 'Hello World!'return render_template("index.html")if __name__ == '__main__':app.run()
如何给html传参使用
模板访问对象属性
通过类传入数据
# app.pyclass User:def __init__(self,username,email):self.username = usernameself.email = email@app.route('/')def hello_world():user=User(username="李四",email="123@qq.com")person={"username":"张三","email":"456@qq.com"}return render_template("index.html",user=user,person=person)#index.html<body>这是传入的名字:{{ user.username }}这是传入的邮箱:{{ user.email }}<br>{{ person['username'] }}{{ person.username }}{{ person['email'] }}{{ person.email }}</body>
过滤器的使用
通过管道符号|
我们在下例中写了两种形式,一种是用现有的比如length,还有一种是我们自定义的,比如这里的dformat
#app.pydef datetime_format(value,format="%Y年%m月%d日 %H时%M分%S秒"):return value.strftime(format)app.add_template_filter(datetime_format,"dformat")@app.route('/filter')def filter():user=User(username="filter",email="123@qq.com")mytime=datetime.now()return render_template("filter.html",user=user,mytime=mytime)#filter.html<body>{{ user.username }}--{{ user.username|length }}<br>{{ mytime }}--{{ mytime|dformat }}</body>
(注:由于使用了datetime,在一开始要通过from datetime import datetime
引入)
控制语句
#app.py@app.route("/control")def control_statement():age=10book=[{"name":"红楼梦","author":"曹雪芹",},{"name":"西游记","author":"吴承恩",}]return render_template("control.html",age=age,book=book)#control.html<body>{% if age>18 %}<div>你大于18岁</div>{% elif age==18 %}<div>你等于18岁</div>{% else %}<div>你小于18岁</div>{% endif %}{% for a in book %}<div>name:{{ a.name }},author:{{ a.author }}</div>{% endfor %}</body>
模板继承
#app.py@app.route("/son")def son():return render_template("children.html")#father.html<body>我是父亲的内容{% block body %}{% endblock %}{% block haha %}{% endblock %}</body>#children.html(此处没有省略内容,就是全部内容,不是像上面只在body区域){% extends "father.html" %}{% block haha %}我是从儿子来的haha{% endblock %}{% block body %}我是从儿子来的body{% endblock %}
jinjia2中加载静态文件
#app.py@app.route('/static')def static_demo():return render_template("static.html")#static.html<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{{ url_for('static',filename='css/style.css') }}"><script src="{{ url_for('static',filename='js/my.js') }}"></script></head><body><img src="{{ url_for('static',filename='images/cat.png') }}" alt=""></body></html>
static静态文件设置如下
结果如下
数据库
先安装好
pip install pymysql
pip install flask-sqlalchemy
Flask连接MySQL数据库
在Navicat Premium中创建数据库
点击测试连接
#app.pyfrom flask import Flaskfrom flask_sqlalchemy import SQLAlchemyfrom sqlalchemy import textapp = Flask(__name__)#MySQL所在的主机名HOSTNAME="127.0.0.1"#MySQL坚挺的端口号,默认3306PORT=3306#连接MySQL的用户名,用自己设置的USERNAME="root"#连接MySQL的密码,用自己设置的PASSWORD="123456"#MySQL上创建的数据库名DATABASE="database_learn"app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}" />#在app.config中设置好链接数据库的信息,#然后使用SQLAlchemy(app)创建一个db对象#SQLAlchemy会自动读取app.config中链接数据库的信息db=SQLAlchemy(app)#测试用的代码with app.app_context():with db.engine.connect() as conn:rs=conn.execute(text("select 1"))print(rs.fetchone())#(1,)表示成功@app.route('/')def hello_world():# put application's code herereturn 'Hello World!'if __name__ == '__main__':app.run()
这段代码用于配置一个 Flask 应用程序以连接到一个 MySQL 数据库。让我解释一下代码的各个部分:
app.config['SQLALCHEMY_DATABASE_URI']
:
这一行代码是在 Flask 应用的配置中设置一个参数,该参数的名称是'SQLALCHEMY_DATABASE_URI'
。这个参数用于指定数据库的连接字符串,告诉应用程序如何连接到数据库。f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
:
这是一个格式化字符串 (f-string),它包含了数据库连接的详细信息。让我们逐个解释它:
mysql+pymysql://
:这部分指定了数据库的类型。在这里,它表示使用 MySQL 数据库,并且使用 PyMySQL 驱动来连接。{USERNAME}
:这是数据库用户名的占位符。通常,你需要将它替换为实际的数据库用户名。{PASSWORD}
:这是数据库密码的占位符。你需要将它替换为实际的数据库密码。{HOSTNAME}
:这是数据库服务器的主机名或 IP 地址的占位符。你需要将它替换为实际的数据库服务器地址。{PORT}
:这是数据库服务器的端口号的占位符。你需要将它替换为实际的数据库服务器端口号。{DATABASE}
:这是数据库的名称的占位符。你需要将它替换为实际的数据库名称。?charset=utf8mb4
:这部分用于设置数据库的字符集。在这里,它将字符集设置为 UTF-8MB4,这通常用于支持多语言和特殊字符。所以,通过这行代码,你告诉 Flask 应用程序使用指定的用户名、密码、主机名、端口号和数据库名来连接到一个 MySQL 数据库,并且使用 UTF-8MB4 字符集。这个连接字符串将被 SQLAlchemy 使用,以便在应用程序中与数据库进行交互。
这段代码执行了一个非常简单的数据库查询。让我解释一下这段代码的执行流程:
with app.app_context()
:
这行代码创建了一个 Flask 应用程序上下文。应用上下文是必要的,当你需要在应用程序的请求/响应周期之外访问应用程序的各个部分时,通常用于执行一些与应用程序相关的操作。with db.engine.connect() as conn
:
这一部分建立了一个数据库连接。它似乎使用了 SQLAlchemy 中的数据库引擎 (db.engine
) 来创建连接,并将其赋值给conn
。这表示你准备与数据库进行交互。rs = conn.execute(text("select 1"))
:
这行代码执行了一个 SQL 查询。它使用了text()
函数创建了一个文本类型的 SQL 查询,这个查询非常简单,只是选择了整数1。然后,execute()
方法将这个查询发送给数据库连接 (conn
) 来执行,并将执行结果存储在rs
中。print(rs.fetchone())
:
这部分代码从查询结果中获取了第一行,并将其打印到控制台上。根据你的注释,查询的结果应该是(1,)
,这表示查询成功,它返回了一个包含值1的元组。所以,这段代码的主要目的是建立一个应用程序上下文、数据库连接,执行一个非常简单的查询以测试数据库连接,并打印查询结果。结果
(1,)
表示查询成功,并且数据库连接已经建立并能够执行查询。这种代码常常用于测试数据库连接或验证数据库是否可用。
ORM模型与表的映射
class User(db.Model):__tablename__ = 'user'id=db.Column(db.Integer,primary_key=True,autoincrement=True)username=db.Column(db.String(100),nullable=False)password=db.Column(db.String(100),nullable=False)with app.app_context():db.create_all()
这段代码涉及到使用 SQLAlchemy 和 Flask 来定义一个数据库模型和创建数据库表格的过程。让我为你解释:
class User(db.Model)
:
这部分代码定义了一个名为User
的数据库模型类。这类通常用于映射到数据库表格。它继承自db.Model
,这表明它是一个 SQLAlchemy 模型。__tablename__ = 'user'
:
这一行指定了数据库表格的名称,即'user'
。数据库表格名称通常与模型类名相同,但小写字母,并且通常使用复数形式,但在这里明确指定了表格名称。- 模型类的属性:
id
: 这是模型类的一个属性,代表用户的唯一标识。它是一个整数字段 (db.Integer
),标记为主键 (primary_key=True
),并且会自动递增 (autoincrement=True
),这意味着每当插入一条新用户记录时,这个字段的值将自动递增,以确保唯一性。username
: 这是用户的用户名字段,它是一个字符串字段 (db.String(100)
),并且不能为空 (nullable=False
),这意味着用户名是必填的。password
: 这是用户的密码字段,它也是一个字符串字段 (db.String(100)
),并且不能为空 (nullable=False
),这意味着密码也是必填的。with app.app_context():
:
这行代码创建了一个 Flask 应用上下文,允许你在应用程序上下文中执行操作。这是必要的,因为你需要在应用程序上下文中创建数据库表格。db.create_all()
:
这行代码使用 SQLAlchemy 中的create_all()
方法来创建数据库表格,具体创建的表格是根据定义的模型类来确定的。在这里,它会创建一个名为 ‘user’ 的数据库表格,该表格与User
模型类相关联。总之,这段代码定义了一个
User
数据库模型类,其中包含了用户的唯一标识、用户名和密码字段。然后,它在应用上下文中使用db.create_all()
来创建与模型相关的数据库表格。这使得你可以在应用程序中存储和检索用户数据。
点击设计表可以看更详细的信息
ORM模型的CRUD操作
@app.route("/user/add")def add_user():#1.创建ORM对象user=User(username='jack',password='123456')#2.将ORM对象添加到db.session中db.session.add(user)#3.将db.session中的改变同步到数据库中db.session.commit()#4.在页面返回结果return "用户创建成功!"@app.route("/user/query")def query_user():#1.get查找:根据主键查找user=User.query.get(1)print(f"{user.id}:{user.username}:{user.password}")#2.filter_by查找#Query:类数组users=User.query.filter_by(username='jack')for user in users:print(user.username)return "数据查找成功"@app.route("/user/update")def update_user():user=User.query.filter_by(username='jack').first()user.password='123'db.session.commit()return "数据修改成功!"@app.route("/user/delete")def delete_user():user=User.query.get(1)db.session.delete(user)db.session.commit()return "数据删除成功!"
让我详细解释每个路由处理函数的代码和功能:
/user/add
– 添加用户
@app.route("/user/add")def add_user():# 1. 创建ORM对象user = User(username='jack', password='123456')# 2. 将ORM对象添加到db.session中db.session.add(user)# 3. 将db.session中的改变同步到数据库中db.session.commit()# 4. 在页面返回结果return "用户创建成功!"
- 这个路由处理函数创建了一个新的用户对象
user
,用户名为 “jack”,密码为 “123456”。 - 将用户对象添加到 SQLAlchemy 的会话 (
db.session
) 中,这相当于将用户信息标记为要插入到数据库中。 - 使用
db.session.commit()
来提交会话中的更改,将用户信息插入到数据库中。 - 返回 “用户创建成功!” 表示成功。
/user/query
– 查询用户
@app.route("/user/query")def query_user():# 1. get查找: 根据主键查找user = User.query.get(1)print(f"{user.id}:{user.username}:{user.password}")# 2. filter_by查找users = User.query.filter_by(username='jack')for user in users:print(user.username)return "数据查找成功"
- 这个路由处理函数首先使用
get()
方法,根据主键(ID)查找 ID 为 1 的用户。 - 然后,使用
filter_by()
方法根据用户名 “jack” 查找所有匹配的用户记录,并将它们存储在users
中。 - 通过迭代
users
对象来打印匹配的用户的用户名。 - 最后,返回 “数据查找成功”。
/user/update
– 更新用户
@app.route("/user/update")def update_user():user = User.query.filter_by(username='jack').first()user.password = '123'db.session.commit()return "数据修改成功!"
- 这个路由处理函数首先使用
filter_by()
方法找到用户名为 “jack” 的用户记录,并获取到第一个匹配的用户。 - 然后,将用户的密码字段修改为 “123”。
- 使用
db.session.commit()
来提交更改,即将用户信息更新到数据库中。 - 返回 “数据修改成功!”。
/user/delete
– 删除用户
@app.route("/user/delete")def delete_user():user = User.query.get(1)db.session.delete(user)db.session.commit()return "数据删除成功!"
- 这个路由处理函数首先使用
get()
方法找到 ID 为 1 的用户记录。 - 然后,使用
db.session.delete(user)
将用户对象从数据库会话中标记为删除。 - 最后,使用
db.session.commit()
来提交更改,即从数据库中删除用户。 - 返回 “数据删除成功!”。
这些路由处理函数演示了如何使用 Flask 和 SQLAlchemy 进行基本的数据库操作,包括添加、查询、更新和删除用户记录。通过 ORM,你可以以面向对象的方式管理数据库操作,使其更加直观和易于理解。这个应用程序针对用户管理提供了基本的增删改查功能。
(每次操作完后,数据库都要刷新一下才能更新,点下面红框里的比较方便)
ORM模型外键与表关系
先在user表里添加一个数据/user/add
class Article(db.Model):__tablename__='article'id=db.Column(db.Integer,primary_key=True,autoincrement=True)title=db.Column(db.String(200),nullable=False)content=db.Column(db.Text,nullable=False)#添加作者的外键author_id=db.Column(db.Integer,db.ForeignKey('user.id'))author=db.relationship("User",backref="articles")@app.route("/article/add")def article_add():article1=Article(title='第一篇文章',content='第一篇文章的内容')article1.author=User.query.get(2)article2=Article(title='第二篇文章',content='第二篇文章的内容')article2.author=User.query.get(2)db.session.add_all([article1,article2])db.session.commit()return "文章添加成功!"@app.route("/article/query")def query_article():user=User.query.get(2)for article in user.articles:print(article.title)return "文章查找成功!"
这两行代码是在SQLAlchemy的模型定义中用来建立数据库表之间关系的重要部分。让我解释一下这两行代码的作用:
author_id=db.Column(db.Integer, db.ForeignKey('user.id'))
:
- 这一行代码定义了一个名为
author_id
的列,它是整数类型(db.Integer
)。- 通过
db.ForeignKey('user.id')
,它创建了一个外键约束,将author_id
列关联到另一个表中的数据。具体来说,它将author_id
列与名为’user’的表中的’id’列关联起来,以建立作者(User)和文章(Article)之间的关系。- 这意味着
author_id
将包含对用户表中特定用户的引用,以指示谁是文章的作者。
author=db.relationship("User", backref="articles")
:
- 这一行代码定义了一个名为
author
的属性,使用db.relationship
来建立模型之间的关系。author
属性创建了一个连接到’User’模型的关系。这表示每个’article’对象都将有一个author
属性,用于指定该文章的作者。backref="articles"
参数在’User’模型中创建一个反向关系,允许您从用户对象访问与该用户相关的所有文章。这就是为什么您可以在query_article
路由中使用user.articles
来获取用户的所有文章的原因。总之,这两行代码一起建立了”Article”和”User”模型之间的关系,使您能够轻松地将文章与其作者关联,并在需要时获取特定用户的所有文章。
如果在数据库中没有
author
属性,那是因为author
是在Python代码中的SQLAlchemy模型中定义的,而不是实际的数据库列。在SQLAlchemy中,author
是一个关系属性,而author_id
是数据库中的外键列。关系属性通常用于在模型中建立表之间的关系,而不会直接映射到数据库表中的列。
当你查询文章对象时,你可以通过article.author
来访问文章的作者,这是因为SQLAlchemy会在运行时执行查询以获取相关的作者。这是ORM(对象关系映射)的优点之一,它允许你在Python中轻松地访问和操作数据库表之间的关系,而不需要手动编写SQL查询。
虽然数据库中没有author
列,但在Python代码中的SQLAlchemy模型中定义的关系属性使你能够方便地访问和管理文章与其作者之间的关系。当你查询文章时,SQLAlchemy会自动执行必要的查询来获取相关的作者信息。
如果我们print(article2.author)
会得到
flask-migrate迁移ORM模型
之前db.create_all()
是有弊端的,如果一个表里新添了某个列,是没办法加上去的
所以我们后面几乎不用这种,改用通过flask-migrate
#添加库from flask_migrate import Migratemigrate=Migrate(app,db)
然后在终端执行这3步
#ORM模型映射成表的3步#1. flask db init:这步只需执行一次#2. flask db migrate :识别ORM模型的改变,生成迁移脚本#3. flask db upgrade:运行迁移脚本,同步到数据库中