笔记 · 2025-03-12

flask小入门笔记

课程链接:

https://www.bilibili.com/video/BV17r4y1y7jJ

第一课 第一个flask项目

项目目录结构:

-项目名
    -static文件夹
    -templates文件夹
    -app.py
from flask import Flask
#使用Flask创建一个app对象,__name__代表当前app.py这个模块
#可以在出现bug时帮助快速定位
#对于寻找模板文件有一个相对路径
app=Flask(__name__)
#创建一个路由和视图函数的映射
@app.route('/'):
def hello_world():
    return 'Hello world!'
if __name__== '__main__':
    app.run()

第二课 配置bug、host和port

from flask import Flask
app=Flask(__name__)
@app.route('/'):
def hello_world():
    return 'Hello world!'
if __name__== '__main__':
    app.run()   

1.debug模式

没有开启该模式,网页不会即时渲染,需要关闭程序重新运行;开启debug后可以即时渲染,只要保存即可,ctrl+s

如果开发的时候出现bug,在浏览器上就可以看到出错信息

开启:PyCharm 中选择Edit configuirations,在弹出的界面中勾选debug

另一种debug开启方式是直接在程序中修改:

app.run(debug=True)

2.host修改

主要作用:

让别的电脑访问你的flask项目

3.修改port端口号

主要的左右:防止端口被占用的情况下项目无法打开,通过修改端口解决问题

第三课 url与视图

from flask import Flask
app=Flask(__name__)
#url协议,http和https+域名+默认80端口和443端口(使用端口但不显示)+路径(代码定义)
#url与视图,即路径(path)和视图的关系


@app.route('/')
def hello_world():
    return 'Hello world!'
    
#新增一个路径
@app.route('/profile')
def profile():
    return '我是个人中心'    
@app.route('/blog/list')
def blog_list():
    return '我是博客列表'
    
if __name__== '__main__':
    app.run()   

@app.route的意思是在app中有一个函数route

定义有参数的url

#带参数的url:将参数固定到了path中
@app.route('/blog/<blog_id>')
def blog_detail(blog_id):
    return f'你访问的博客是{blog_id}'
#/book/list:会返回第一页的数据
#/book/list?page=2 :会获取第二页的数据
#为什么同一个url可以不带参数又可以带?
#这是使用查询字符串的方式传参
from falsk import request
...
@app.route('/book/list')
def book_list():
    #arguments:参数
    #request.args:类字典类型
    request.args.get("page",default=1,type=int)
    return f"你获取的是第{page}的图书列表"
...

第四课 模板渲染

默认的为jinja2库的渲染,会在安装flask时自动安装

jinja模板放在templates文件夹中,为html文件

#app.py
from flask import Flask,render_template
app=Flask(__name__)
@app.route('/'):
def hello_world():
    #自动在templates文件夹中找到index.html并渲染返回
    return render_template('index.html')
    
@app.route('/blog/<blog_id>')
def blog_detail(blog_id):
    #把blog_id传给blog_detail.html
    return render_template("blog_detail.html",blog_id=blog_id,username='了然')


if __name__== '__main__':
    app.run()   

在blog_detail.html中使用传入的参数

<h1>你访问的博客详情是:{{ blog_id }}</h1>
<p>你的用户名是:{{ username }}</p>

第五课 模板访问对象属性

#app.py
from flask import Flask,render_template
app=Flask(__name__)

class User:
    def __init__(self,username,email):
    self.username=username
    self.email=email

@app.route('/'):
def hello_world():
    #创建user对象
    user=User(username="了然",email="222222@qq.com")
    return render_template('index.html',user=user)
    
@app.route('/test2')
def test2(blog_id):
    #为字典的传入时
    person={
        "username":"张三",
        "email":"2222222@qq.com"
    }
    return render_template("test2.html",person=person)


if __name__== '__main__':
    app.run()   

在jinja中使用

#对象使用
{{ user.username }}/{{ user.email }}
#字典使用,都可以
{{ person['username'] }}/{{ person.email }}

第六课 过滤器的使用

管道操作符:|

@app.route("/filter")
def fileter_demo():
    user=User(username="了然",email="222222@qq.com")
    return render_template("filter.html",user=user)

filter.html

{{ user.username }}
{{ 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 }} → 随机输出其中一个数字

自定义过滤器

定义一个函数

from datetime import datetime

def datetime_format(value,format="%Y-%m-%d-%H:%M"):
    return value.strftime(format)
    
app.add_template_filter(datetime_format,"dformat")

@app中
    mytime=datetime.now()
    return render_template("test.html",mytime=mytime)

相应的test.html中使用:

{{ mytime|dformat }}
#显示2024-03-07-11:05

第七课 控制语句

@app.route('/control')
def control_html():
    age=17
    return render_template('control.html',age=age)

control.html,换句话说,使用{%%}的就是python代码

#使用if语句
{% if age>18 %}
    <div>大于18岁,可以sese了</div>
{% elif age==18%}
    <div>刚满18岁,请斟酌</div>
{% else %}
    <div>不到18岁,不可以sese</div>
{% endif %}
#注意一定要有endif

for循环

{% for book in books %}
    #使用book,只能一次循环完成
    {{ book.name }}

{% endfor %}

第八课 模版继承

原因:网站有很多重复或固定元素,如果这些重复元素每次都要写代码增加工作量,所以使用模版继承的方式,直接从模版调用,减少工作量

base.html-父模版
<h1>我是父模板的标题</h1>
#变动的标题设计
<h1>{% block tilte %}{% endblock %}</h1>[x]
<body>
{% block body %}
{% endblock %}
</body>
child.html-子模板
{% extends "base.html" %}
#继承父模板

#使用父模板的block
{% block title %}
我是子模板的标题 
#[将替代父模板x处]
{% endblock %}

#body类似
@app.route("/child")
def child():
    return render_template("child.html")

使用后,子模板会继承父模板的内容,变化的内容如何实现?

使用block模块

第九课 加载静态文件

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

加载图片

<img src="{{ url_for('static',filename='mm.jpg') }}">
#filename文件夹以static文件夹为根目录开始寻找

加载css或js,如static文件夹中有css文件夹和js文件夹

#引入方法
<link rel='stylesheet' href="{{ url_for('static',filename='css/style.css') }}" >

<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作为案例,安装方法:

pip install pymysql

flask-sqlalchemy:用python代码简单操作数据库的库,而不用数据库本身的操作代码。

安装方法:

pip install flask-sqlalchemy

连接mysql

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
#在app.config中设置连接好的数据库信息
#使用SQLAlchemy(app)创建一个db对象
#SQLAlchemy会自动读取app.config中连接数据库的对象
app=Flask(__name__)
#配置
HOSTNAME="127.0.0.1"
PORT="默认端口3306"
USERNAME="数据库账户"
PASSWORD="数据库密码"
DATABASE="数据库名"
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"

#首先要有相应的数据库,以上代码无法创建一个新的数据库或表,仅仅是数据库连接的配置
#字符串集tf8mb4是更好的utf8字符集


db=SQLAlchemy(app)

@app.route('/')
def hello_world():
    return "hello world!"
    
    
if __name__=='__main__':
    app.run

由于mysql数据库太难部署了,所以我个人在学习的时候使用小皮面板启动后简单搭建了一个mysql数据库。

下载小皮面板:https://www.xp.cn/php-study

解压安装:

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

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

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app=Flask(__name__)
#配置
HOSTNAME="127.0.0.1"
PORT="3306"
USERNAME="root"
PASSWORD="root"
DATABASE="root"
app.config['SQLALCHEMY_DATABASE_URI']=f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
#测试数据库是否连接成功
db = SQLAlchemy(app)

try:
    with app.app_context():
        with db.engine.connect() as conn:
            # 使用 text 函数包装 SQL 语句
            rs = conn.execute(text("select 1"))
            print(rs.fetchone())  # (1,)
    print("数据库连接成功!")
except Exception as e:
    print(f"数据库连接失败:{e}")

@app.route('/')
def hello_world():
    return "hello world!"

if __name__ == '__main__':
    # 如果遇到一些权限错误,可以指定端口来解决问题
    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模型,即创建了这样的一个表

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)

#使用,如创建:
user=User(username='your username',password='your password')

模型映射同步到数据库中

#注意应用上下文的问题
with app.app_context():
    db.create_all()

第十二课 ORM模型的CRUD操作

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)


@app.route("/user/add")
def add_user():
#创建orm对象
    user=User(username='your username',password='your password')
    #将orm对象添加到db.session中
    db.session.add(user)
    #多个用户,多个db.session.add(user)
    #同步到数据库
    db.session.commit()
    return "用户创建成功!"

验证,打开数据库表即可发现:

查询

@app.route('/user/query')
def query_user():
    #1.get查找:根据主键查找
    user=User.query.get(1)
    print(f'找到用户:{user},{user.username},{user.password}')
    return "查找成功!"
    #2.filter_by查找,查找多个
    users=User.query.fileter_by(username="张三")
    for user in users:
        print(user)#一个query对象

更多查找操作,可根据ai补充

修改

def updata_user()
    user=User.query.filter_by(username='张三').first()#返回user对象,使用first时
    user.password="222222"
    db.sesson.commit()
    return "数据修改成功!"

这样密码就修改了

删除

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

第十三课 ORM模型与外键的关系**

表关系

关系型数据库一个强大的功能,就是多个表之间可以建立关系。

比如文章表中,通常需要保存作者数据,但是我们不需要直接把作者数据放到文章表中,而是通过外键引用用户表。

这种强大的表关系,可以存储非常复杂的数据,并且可以让查询非常迅速。在 Flask-SQLAlchemy 中,同样也支持表关系的建立。表关系建立的前提,是通过数据库层面的外键实现的。表关系总体来讲可以分为三种,分别是:一对多(多对一)、一对一、多对多。以下分别进行讲解。

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"))

建立关系

以上通过外键,实际上已经建立起一对多的关系,一篇文章只能引用一个作者,但是一个作者可以被多篇文章引用。但是以上只是建立了一个外键,通过 Article 的对象,还是无法直接获取到 author_id 引用的那个 User 对象。为了达到操作 ORM 对象就跟操作普通 Python 对象一样,Flask-SQLAlchemy 提供了 db.relationship 来引用外键所指向的那个 ORM 模型。在以上的 Article 模型中,我们添加 db.relationship,示例代码如下:

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")

我们添加了一个 author 属性,这个属性通过 db.relationship 与 User 模型建立了联系,以后通过 Article 的实例对象访问 author 的时候,比如 article.author,那么 Flask-SQLAlchemy 会自动根据外键 author_id 从 user 表中寻找数据,并形成 User 模型实例对象。以下我们通过创建 Article 对象,并通过访问 Article 实例对象上的 author 属性来关联 User 对象,示例代码如下:

@app.route('/article/add')
def article_add():
    user = User.query.first()
    article = Article(title="aa", content="bb", author=user)
    db.session.add(article)
    db.session.commit()
    article = Article.query.filter_by(title="aa").first()
    print(article.author.username)

以上代码中,我们先是创建了一个 article 对象并添加到数据库中,接下来再从数据库中提取,然后通过 article.author.username 可以访问到对应的用户名

以上的单向的关系,可以通过文章找到user,如果双向关系,该怎么做呢?

#方法1
#先在User对象中,创建articles的back_populates
articles=db.relationship("Article",back_populates="author")
#然后到Article对象中一一对应
author=db.relationship("User",back_populates="articles")

#方法2,直接在Article对象中使用backref,会自动给User模型添加一个articles的属性
author=db.relationship("User",backref="articles")
#如果要更新多个数据,可以使用add_all
db.session.add_all([data1,data2...])
de.session.commit()
#使用,根据用户查找文章标题,如果内容为article.content
@app.route("/article/query")
def query_article():
    user = User.query.get(2)
    for article in user.articles:
        print(article.title)
    return "文章查找成功!"

第十四课 flask-migrate迁移ORM模型

db.create_all()无法即时更新你的orm模型的字段内容,所以需要这个插件,安装:

pip install flask-migrate
from flask_migrate import Migrate
#创建一个迁移对象
migrate=Migrate(app,db)

####在控制台依次执行命令 ####1.flask db init —-只需要执行一次

会多一个文件夹,是迁移脚本文件

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

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

目录