课程链接:
https://www.bilibili.com/video/BV17r4y1y7jJ
第一课 第一个flask项目
项目目录结构:
1 -项目名
2 -static文件夹
3 -templates文件夹
4 -app.py
1 from flask import Flask
2 #使用Flask创建一个app对象,__name__代表当前app.py这个模块
3 #可以在出现bug时帮助快速定位
4 #对于寻找模板文件有一个相对路径
5 app=Flask(__name__)
6 #创建一个路由和视图函数的映射
7 @app.route('/'):
8 def hello_world():
9 return 'Hello world!'
10 if __name__== '__main__':
11 app.run()
第二课 配置bug、host和port
1 from flask import Flask
2 app=Flask(__name__)
3 @app.route('/'):
4 def hello_world():
5 return 'Hello world!'
6 if __name__== '__main__':
7 app.run()
1.debug模式
没有开启该模式,网页不会即时渲染,需要关闭程序重新运行;开启debug后可以即时渲染,只要保存即可,ctrl+s
如果开发的时候出现bug,在浏览器上就可以看到出错信息
开启:PyCharm 中选择Edit configuirations,在弹出的界面中勾选debug


另一种debug开启方式是直接在程序中修改:
1 app.run(debug=True)
2.host修改

主要作用:
让别的电脑访问你的flask项目

3.修改port端口号


主要的左右:防止端口被占用的情况下项目无法打开,通过修改端口解决问题
第三课 url与视图
1 from flask import Flask
2 app=Flask(__name__)
3 #url协议,http和https+域名+默认80端口和443端口(使用端口但不显示)+路径(代码定义)
4 #url与视图,即路径(path)和视图的关系
5
6
7 @app.route('/')
8 def hello_world():
9 return 'Hello world!'
10
11 #新增一个路径
12 @app.route('/profile')
13 def profile():
14 return '我是个人中心'
15 @app.route('/blog/list')
16 def blog_list():
17 return '我是博客列表'
18
19 if __name__== '__main__':
20 app.run()
@app.route的意思是在app中有一个函数route

定义有参数的url
1 #带参数的url:将参数固定到了path中
2 @app.route('/blog/<blog_id>')
3 def blog_detail(blog_id):
4 return f'你访问的博客是{blog_id}'

1 #/book/list:会返回第一页的数据
2 #/book/list?page=2 :会获取第二页的数据
3 #为什么同一个url可以不带参数又可以带?
4 #这是使用查询字符串的方式传参
5 from falsk import request
6 ...
7 @app.route('/book/list')
8 def book_list():
9 #arguments:参数
10 #request.args:类字典类型
11 request.args.get("page",default=1,type=int)
12 return f"你获取的是第{page}的图书列表"
13 ...

第四课 模板渲染
默认的为jinja2库的渲染,会在安装flask时自动安装
jinja模板放在templates文件夹中,为html文件

1 #app.py
2 from flask import Flask,render_template
3 app=Flask(__name__)
4 @app.route('/'):
5 def hello_world():
6 #自动在templates文件夹中找到index.html并渲染返回
7 return render_template('index.html')
8
9 @app.route('/blog/<blog_id>')
10 def blog_detail(blog_id):
11 #把blog_id传给blog_detail.html
12 return render_template("blog_detail.html",blog_id=blog_id,username='了然')
13
14
15 if __name__== '__main__':
16 app.run()
在blog_detail.html中使用传入的参数
1 <h1>你访问的博客详情是:{{ blog_id }}</h1>
2 <p>你的用户名是:{{ username }}</p>
第五课 模板访问对象属性
1 #app.py
2 from flask import Flask,render_template
3 app=Flask(__name__)
4
5 class User:
6 def __init__(self,username,email):
7 self.username=username
8 self.email=email
9
10 @app.route('/'):
11 def hello_world():
12 #创建user对象
13 user=User(username="了然",email="222222@qq.com")
14 return render_template('index.html',user=user)
15
16 @app.route('/test2')
17 def test2(blog_id):
18 #为字典的传入时
19 person={
20 "username":"张三",
21 "email":"2222222@qq.com"
22 }
23 return render_template("test2.html",person=person)
24
25
26 if __name__== '__main__':
27 app.run()
在jinja中使用
1 #对象使用
2 {{ user.username }}/{{ user.email }}
3 #字典使用,都可以
4 {{ person['username'] }}/{{ person.email }}
第六课 过滤器的使用
管道操作符:|
1 @app.route("/filter")
2 def fileter_demo():
3 user=User(username="了然",email="222222@qq.com")
4 return render_template("filter.html",user=user)
filter.html
1 {{ user.username }}
2 {{ user.username|length }}#获取username的长度
过滤器有内置的也可以自定义
以下是内置的一些过滤器:
过滤器名称 | 功能描述 | 使用方法及示例 |
abs | 返回数值的绝对值 | {{ -5|abs }} → 输出 5 |
capitalize | 将字符串首字母大写,其余小写 | {{ “hello”||capitalize }} → 输出 Hello |
default | 变量未定义时显示默认值 | {{ name|default(“未命名”) }} (若boolean=True,则变量为False时也触发,如空字符串、空列表等) |
escape / e | 转义HTML特殊字符(默认开启全局转义) | {{ “<script>”|escape }} → 输出 <script> |
float | 将值转换为浮点数 | {{ “3.14”|float }} → 输出 3.14 |
int | 将值转换为整数 | {{ “42”|int }} → 输出 42 |
join | 用指定分隔符拼接列表 | {{ [“a”, “b”]|join(“-“) }} → 输出 a-b |
length | 返回序列或字典的长度 | {{ [1,2,3]|length }} → 输出 3 |
lower | 将字符串转为小写 | {{ “HELLO”|lower }} → 输出 hello |
upper | 将字符串转为大写 | {{ “hello”|upper }} → 输出 HELLO |
replace | 替换字符串中的指定内容 | {{ “Hello World”|replace(“World”, “Jinja”) }} → 输出 Hello Jinja |
reverse | 反转序列或字符串 | {{ “abc”|reverse }} → 输出 cba |
safe | 标记字符串为安全HTML(关闭转义) | {{ “<em>文本</em>”|safe }} → 直接渲染HTML |
slice | 对序列进行切片 | {{ [1,2,3,4]|slice(2) }} → 输出 [[1,2], [3,4]] |
sort | 对序列排序(支持reverse=True和attribute参数) | {{ students|sort(attribute=’name’) }} {{ [3,1,2]|sort(reverse=True) }} → [3,2,1] |
striptags | 删除HTML标签 | {{ “<p>文本</p>”|striptags }} → 输出 文本 |
title | 将每个单词首字母大写 | {{ “hello world”|title }} → 输出 Hello World |
trim | 去除字符串首尾空格 | {{ ” hello “|trim }} → 输出 hello |
truncate | 截断字符串并添加省略号 | {{ “Long text here”|truncate(7) }} → Long… (killwords=True保留完整单词) |
dictsort | 按字典键或值排序 | {{ {2:’b’,1:’a’}|dictsort }} → 按键排序为 [(1, ‘a’), (2, ‘b’)] |
filesizeformat | 将字节数转换为易读的文件大小(如1.3 MB) | {{ 2048|filesizeformat }} → 输出 2 KB |
groupby | 按属性对对象列表分组 | {% for city, items in users|groupby(‘city’) %} → 按城市分组 |
random | 从序列中随机选择一个元素 | {{ [1,2,3]|random }} → 随机输出其中一个数字 |
自定义过滤器
定义一个函数
1 from datetime import datetime
2
3 def datetime_format(value,format="%Y-%m-%d-%H:%M"):
4 return value.strftime(format)
5
6 app.add_template_filter(datetime_format,"dformat")
7
8 @app中
9 mytime=datetime.now()
10 return render_template("test.html",mytime=mytime)
相应的test.html中使用:
1 {{ mytime|dformat }}
2 #显示2024-03-07-11:05
第七课 控制语句
1 @app.route('/control')
2 def control_html():
3 age=17
4 return render_template('control.html',age=age)
control.html,换句话说,使用{%%}的就是python代码
1 #使用if语句
2 {% if age>18 %}
3 <div>大于18岁,可以sese了</div>
4 {% elif age==18%}
5 <div>刚满18岁,请斟酌</div>
6 {% else %}
7 <div>不到18岁,不可以sese</div>
8 {% endif %}
9 #注意一定要有endif
for循环
1 {% for book in books %}
2 #使用book,只能一次循环完成
3 {{ book.name }}
4
5 {% endfor %}
第八课 模版继承
原因:网站有很多重复或固定元素,如果这些重复元素每次都要写代码增加工作量,所以使用模版继承的方式,直接从模版调用,减少工作量
1 base.html-父模版
2 <h1>我是父模板的标题</h1>
3 #变动的标题设计
4 <h1>{% block tilte %}{% endblock %}</h1>[x]
5 <body>
6 {% block body %}
7 {% endblock %}
8 </body>
1 child.html-子模板
2 {% extends "base.html" %}
3 #继承父模板
4
5 #使用父模板的block
6 {% block title %}
7 我是子模板的标题
8 #[将替代父模板x处]
9 {% endblock %}
10
11 #body类似
1 @app.route("/child")
2 def child():
3 return render_template("child.html")
使用后,子模板会继承父模板的内容,变化的内容如何实现?
使用block模块
第九课 加载静态文件
1 @app.route('/static')
2 def static():
3 return render_template('static.html')
加载图片
1 <img src="{{ url_for('static',filename='mm.jpg') }}">
2 #filename文件夹以static文件夹为根目录开始寻找
加载css或js,如static文件夹中有css文件夹和js文件夹
1 #引入方法
2 <link rel='stylesheet' href="{{ url_for('static',filename='css/style.css') }}" >
3
4 <script src="{{ url_for('static',filename='js/myjs.js') }}"></script>
加载static时,都以static目录为根目录。
第十课 flask连接数据库
flask操作数据库,需要安装第三方库。在python中,目前有如下MySQL驱动板包:
MySQL-python:仅支持python2,不考虑。
mysqlclient:是MySQL-python的分支,支持python3且修复了一些bug,但安装的时候容易因环境问题出错。
pymysql:纯python实现的驱动包,效率不如mysqlclient,但可与python无缝衔接。
Mysql-connector-python:MySQL官方推出的纯python连接其数据库的驱动,执行效率比pymysql还慢。
课程以pymysql作为案例,安装方法:
1 pip install pymysql

flask-sqlalchemy:用python代码简单操作数据库的库,而不用数据库本身的操作代码。
安装方法:
1 pip install flask-sqlalchemy
连接mysql
1 from flask import Flask
2 from flask_sqlalchemy import SQLAlchemy
3 #在app.config中设置连接好的数据库信息
4 #使用SQLAlchemy(app)创建一个db对象
5 #SQLAlchemy会自动读取app.config中连接数据库的对象
6 app=Flask(__name__)
7 #配置
8 HOSTNAME="127.0.0.1"
9 PORT="默认端口3306"
10 USERNAME="数据库账户"
11 PASSWORD="数据库密码"
12 DATABASE="数据库名"
13 app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
14
15 #首先要有相应的数据库,以上代码无法创建一个新的数据库或表,仅仅是数据库连接的配置
16 #字符串集tf8mb4是更好的utf8字符集
17
18
19 db=SQLAlchemy(app)
20
21 @app.route('/')
22 def hello_world():
23 return "hello world!"
24
25
26 if __name__=='__main__':
27 app.run
由于mysql数据库太难部署了,所以我个人在学习的时候使用小皮面板启动后简单搭建了一个mysql数据库。
下载小皮面板:https://www.xp.cn/php-study
解压安装:

安装完成后,点击mysql右侧的启动按钮(必选),同时启动Nginx或Apache服务器(二选一)。

点击左侧数据库,即可获取数据库名和密码等信息,当然你也可以修改密码,或重新创建一个数据库。(如果root本身的数据库无法连接,可以自己建立一个数据库。)

1 from flask import Flask
2 from flask_sqlalchemy import SQLAlchemy
3
4 app=Flask(__name__)
5 #配置
6 HOSTNAME="127.0.0.1"
7 PORT="3306"
8 USERNAME="root"
9 PASSWORD="root"
10 DATABASE="root"
11 app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
12 #测试数据库是否连接成功
13 db = SQLAlchemy(app)
14
15 try:
16 with app.app_context():
17 with db.engine.connect() as conn:
18 # 使用 text 函数包装 SQL 语句
19 rs = conn.execute(text("select 1"))
20 print(rs.fetchone()) # (1,)
21 print("数据库连接成功!")
22 except Exception as e:
23 print(f"数据库连接失败:{e}")
24
25 @app.route('/')
26 def hello_world():
27 return "hello world!"
28
29 if __name__ == '__main__':
30 # 如果遇到一些权限错误,可以指定端口来解决问题
31 app.run(port=5001)
结果:

第十一课 ORM模型与表的映射
对象关系映射(Object Relationship Mapping),简称 ORM,是一种可以用 Python 面向对象的方式来操作关系型数据库的技术,具有可以映射到数据库表能力的 Python 类我们称之为 ORM 模型。
一个 ORM 模型与数据库中一个表相对应,ORM 模型中的每个类属性分别对应表的每个字段,ORM 模型的每个实例对象对应表中每条记录。
ORM 技术提供了面向对象与 SQL 交互的桥梁,让开发者用面向对象的方式操作数据库,使用 ORM 模型具有以下优势:
(1)开发效率高:几乎不需要写原生 SQL 语句,使用纯 Python 的方式操作数据库,大大的提高了开发效率。
(2)安全性高:ORM 模型底层代码对一些常见的安全问题,比如 SQL 注入做了防护,比直接使用 SQL 语句更加安全。
(3)灵活性强:Flask-SQLAlchemy 底层支持 SQLite、MySQL、Oracle、PostgreSQL 等关系型数据库,但针对不同的数据库,ORM 模型代码几乎一模一样,只需修改少量代码,即可完成底层数据库的更换。
创建一个user模型,即创建了这样的一个表
1 class User(db.Model):
2 __tablename__="user"
3 id=db.Column(db.Integer,primary_key=True,autoincrement=True)#设置第一列,且指定主键,且自增
4 username=db.Column(db.String(100),nullable=False)
5 password=db.Column(db.String(100),nullable=False)
6
7 #使用,如创建:
8 user=User(username='your username',password='your password')
模型映射同步到数据库中
1 #注意应用上下文的问题
2 with app.app_context():
3 db.create_all()

第十二课 ORM模型的CRUD操作
1 class User(db.Model):
2 __tablename__="user"
3 id=db.Column(db.Integer,primary_key=True,autoincrement=True)#设置第一列,且指定主键,且自增
4 username=db.Column(db.String(100),nullable=False)
5 password=db.Column(db.String(100),nullable=False)
6
7
8 @app.route("/user/add")
9 def add_user():
10 #创建orm对象
11 user=User(username='your username',password='your password')
12 #将orm对象添加到db.session中
13 db.session.add(user)
14 #多个用户,多个db.session.add(user)
15 #同步到数据库
16 db.session.commit()
17 return "用户创建成功!"
验证,打开数据库表即可发现:

查询
1 @app.route('/user/query')
2 def query_user():
3 #1.get查找:根据主键查找
4 user=User.query.get(1)
5 print(f'找到用户:{user},{user.username},{user.password}')
6 return "查找成功!"
7 #2.filter_by查找,查找多个
8 users=User.query.fileter_by(username="张三")
9 for user in users:
10 print(user)#一个query对象
更多查找操作,可根据ai补充
修改
1 def updata_user()
2 user=User.query.filter_by(username='张三').first()#返回user对象,使用first时
3 user.password="222222"
4 db.sesson.commit()
5 return "数据修改成功!"
这样密码就修改了

删除
1 def delete_user():
2 user=User.query.get(1)
3 #以上操作都需要先找到
4 db.session.delete(user)
5 db.session.commit()
6 return "删除成功!"

第十三课 ORM模型与外键的关系**
表关系
关系型数据库一个强大的功能,就是多个表之间可以建立关系。
比如文章表中,通常需要保存作者数据,但是我们不需要直接把作者数据放到文章表中,而是通过外键引用用户表。
这种强大的表关系,可以存储非常复杂的数据,并且可以让查询非常迅速。在 Flask-SQLAlchemy 中,同样也支持表关系的建立。表关系建立的前提,是通过数据库层面的外键实现的。表关系总体来讲可以分为三种,分别是:一对多(多对一)、一对一、多对多。以下分别进行讲解。
1 Class Article(db.Model):
2 __tablename__="article"
3 id=db.Column(db.Integer,primary_key=True,autoincrement=True)
4 title=db.Column(db.String(200),nullable=False)
5 content=db.Column(db.Text,nullable=False)
6
7
8 #添加作者的外键
9 author_id=db.Column(db.Integer,db.ForeignKey("user.id"))
建立关系
以上通过外键,实际上已经建立起一对多的关系,一篇文章只能引用一个作者,但是一个作者可以被多篇文章引用。但是以上只是建立了一个外键,通过 Article 的对象,还是无法直接获取到 author_id 引用的那个 User 对象。为了达到操作 ORM 对象就跟操作普通 Python 对象一样,Flask-SQLAlchemy 提供了 db.relationship 来引用外键所指向的那个 ORM 模型。在以上的 Article 模型中,我们添加 db.relationship,示例代码如下:
1 class Article(db.Model):
2 tablename = "article"id = db.Column(db.Integer, primary_key=True, autoincrement=True)
3 title = db.Column(db.String(200), nullable=False)
4 content = db.Column(db.Text, nullable=False)
5 author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
6 author = db.relationship("User")
我们添加了一个 author 属性,这个属性通过 db.relationship 与 User 模型建立了联系,以后通过 Article 的实例对象访问 author 的时候,比如 article.author,那么 Flask-SQLAlchemy 会自动根据外键 author_id 从 user 表中寻找数据,并形成 User 模型实例对象。以下我们通过创建 Article 对象,并通过访问 Article 实例对象上的 author 属性来关联 User 对象,示例代码如下:
1 @app.route('/article/add')
2 def article_add():
3 user = User.query.first()
4 article = Article(title="aa", content="bb", author=user)
5 db.session.add(article)
6 db.session.commit()
7 article = Article.query.filter_by(title="aa").first()
8 print(article.author.username)
以上代码中,我们先是创建了一个 article 对象并添加到数据库中,接下来再从数据库中提取,然后通过 article.author.username 可以访问到对应的用户名
以上的单向的关系,可以通过文章找到user,如果双向关系,该怎么做呢?
1 #方法1
2 #先在User对象中,创建articles的back_populates
3 articles=db.relationship("Article",back_populates="author")
4 #然后到Article对象中一一对应
5 author=db.relationship("User",back_populates="articles")
6
7 #方法2,直接在Article对象中使用backref,会自动给User模型添加一个articles的属性
8 author=db.relationship("User",backref="articles")
9
1 #如果要更新多个数据,可以使用add_all
2 db.session.add_all([data1,data2...])
3 de.session.commit()
1 #使用,根据用户查找文章标题,如果内容为article.content
2 @app.route("/article/query")
3 def query_article():
4 user = User.query.get(2)
5 for article in user.articles:
6 print(article.title)
7 return "文章查找成功!"
第十四课 flask-migrate迁移ORM模型
db.create_all()无法即时更新你的orm模型的字段内容,所以需要这个插件,安装:
1 pip install flask-migrate
1 from flask_migrate import Migrate
2 #创建一个迁移对象
3 migrate=Migrate(app,db)
4
####在控制台依次执行命令 ####1.flask db init —-只需要执行一次
会多一个文件夹,是迁移脚本文件

####2.flask db migrate ——-识别ORM模型的改变,生成迁移脚本

####3.flask db upgrade ——-执行迁移脚本程序完成更新,数据库完成同步