笔记 · 2025-03-12

flask小入门笔记

课程链接:

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 }} → 输出 &lt;script&gt;
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 ——-执行迁移脚本程序完成更新,数据库完成同步

目录