舌吻 发表于 2023-2-1 01:46:36

初识Flask

初识Flask

Flask简介

Flask是一个基于Python的web框架,由奥地利开发商Armin Ronacher于2010年4月1日发布。它以灵活、“微”框架著称,其本身并不具备太多的功能,但通过丰富的第三方插件,使其在保持重量轻和简单的同时仍然可以进行高度扩展,让开发者能轻松应对现实开发中复杂的需求。
Flask vs Django



[*]Django功能大而全,Flask只包含基本的配置;
[*]Flask 比 Django 扩展性更好。
安装Flask

打开cmd窗口,执行如下指令即可安装。
pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple 执行如下指令查看是否安装成功。
pip list 第一个Flask项目(使用Pycharm)

打开PyCharm,选择New Project新建一个项目,之后点击左侧Flask,再选择项目存放路径以及Python解释器路径,点击Create即可。

创建成功后,项目结构如下。
flask_01
│app.py:项目入口文件。
├─static:存放静态文件(js、css、image等)的文件夹,初始为空。
└─templates:存Jinjia2模板的文件夹,初始为空。

app.py初始内容如下。
from flask import Flask# 从flask包中导入Flask类

app = Flask(__name__)# 实例化Flask类
# __name__:代表当前app.py这个模块,其作用为 1.以后出现bug,可以帮助我们快速定位;2.对于寻找模板文件,有一个相对路径


@app.route('/')# 创建一个路由和视图函数的映射,/代表根路由
def hello_world():# 当访问根路由时会执行此函数
    return 'Hello World!'


if __name__ == '__main__':
    app.run()# 运行项目 项目配置

debug模式

开启debug模式后,只要修改代码后保存,项目就会重新加载,无需手动重启项目,且开发时如果遇到bug,可以在浏览器上看到出错信息。
设置方法

法一

首先点击Edit Configurations。

勾选FLASK_DEBUG后,点击OK即可。

法二

在app.run()中添加debug=True。
app.run(debug=True)# 运行项目 修改host

host即为监听的主机名,默认为127.0.0.1,修改host可以让其它电脑也能访问到本电脑的flask项目,修改步骤如下。
点击Edit Configurations。

在Additional options处填写预设的host值,然后点击OK即可。

修改port

port即为端口号,若要修改,同样在Additional options处修改即可。

URL与视图

URL格式

协议://域名:端口号/path,其中,path通过app.route()指定。
URL与视图的关系

在URL中,http协议默认端口为80,https协议默认端口为443,在实际使用中默认端口号可以不填写,下方两个URL均能正确访问到百度地址。
https://www.baidu.com
https://www.baidu.com:443
定义无参数的URL

敲写下方代码,程序运行后,可通过127.0.0.1:8888/home访问。
@app.route('/home')
def home():
    return 'home' 定义有参数的URL

flask里通过来给path指定参数。
参数类型


[*] string:字符串类型,可以接受除/以外的字符。

[*] int:整型,可以接受能通过int()方法转换的字符。

[*] float:浮点型,可以接受能通过float()方法转换的字符。

[*] path:路径,类似string,但是中间可以添加/。

[*] uuid:UUID类型,UUID是一组32位数的16进制所构成。

[*] any:备选值中的任何一个(理解为枚举)。

类型一

敲写下方代码,程序运行后,可通过   127.0.0.1:8888/home/任意数字访问。
@app.route('/home/<int:user_id>')# 类型的指定是可选的
def blog_detail(user_id):
    return '您是:%s' % user_id
类型二

敲写下方代码,程序运行后,可通过   127.0.0.1:8888/book/list?page=任意数字访问。
from flask import Flask, request# 从flask包中导入Flask类

# /book/list:返回第一页的数据
# /book/list?page=2:返回第二页的数据

@app.route('/book/list')
def book_list():
    # arguments: 参数
    # request.args: 类字典类型
    page = request.args.get("page", default=1, type=int)
    return f'您获取的是第{page}页的图书列表'
Jinjia2模板

Jinjia2是一个Python模板语言,安装Flask时,Jinjia2会自动安装,Jinjia2模板语言是不分缩进的。
模板渲染

无参数渲染

在templates创建文件index.html。
index.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1>这是首页。</h1>
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

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


if __name__ == '__main__':
    app.run()# 运行项目 有参数渲染

在templates创建文件user_detail.html。
user_detail.html内容如下,Jinjia2通过{}来获取变量的值。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户详情</title>
</head>
<body>
    <h1>用户id是{{ user_id }}</h1>
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/home/<user_id>')
def user_detail(user_id):
    return render_template('user_detail.html', user_id=user_id)


if __name__ == '__main__':
    app.run()# 运行项目 模板访问对象属性

Jinjia2访问对象属性有两种方法,例如{{ user.user_name }}和{{ user['user_name'] }}。
index.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>{{ user.user_name }} + {{ user.user_email }}</h1>
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

class User:
    def __init__(self, user_name, user_email):
      self.user_name = user_name
      self.user_email = user_email

@app.route('/')
def hello_world():
    user = User("lili", '123456@qq.com')
    return render_template('index.html', user=user)


if __name__ == '__main__':
    app.run() 过滤器

在Python中,如果需要对某个变量进行处理,可以通过函数来实现;在模板中,则是通过过滤器来实现的。过滤器本质上也是函数,在模板中使用管道符号(|)来调用。例如有字符串类型变量name,想要获取它的长度,可以通过{{name | length}}来获取,length是Jinjia2内置的过滤器,Jinjia2会把name当做第一个参数传给length过滤器底层对应的函数。
内置过滤器

filter.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filter_demo</title>
</head>
<body>
    名字:{{ user.user_name }}
    名字长度:{{ user.user_name|length }}
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

class User:
    def __init__(self, user_name, user_email):
      self.user_name = user_name
      self.user_email = user_email

@app.route('/filter')
def filte_page():
    user = User('lili', '123@qq.com')
    return render_template('filter.html', user=user)

if __name__ == '__main__':
    app.run() 自定义过滤器

过滤器本质上是Python的函数,它会把被过滤的值当做第一个参数传给这个函数,函数经过一些逻辑处理后,再返回新的值。在过滤器函数写好后,可以通过@app.template_filter装饰器或者app.add_template_filter函数来把函数注册成Jinjia2能用的过滤器。
下方代码定义了一个date_format函数,第一个参数是需要被处理的值,第二个参数是时间的格式,并且指定了一个默认值,通过app.add_template_filter,将date_format函数注册成了过滤器,并且过滤器的名字为d_format,如果app.add_template_filter没有传第二个参数,那么默认将使用函数的名称来作为过滤器的名称。
filter.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filter_demo</title>
</head>
<body>
    时间:{{ my_time|d_format }}
</body>
</html> app.py内容如下。
from flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)

@app.route('/filter')
def filte_page():
    my_time = datetime.now()
    return render_template('filter.html', my_time=my_time)


def date_format(value, format="%Y-%m-%d %H:%M"):
    return value.strftime(format)


app.add_template_filter(date_format, 'd_format')

if __name__ == '__main__':
    app.run() 控制语句

if语句

filter.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filter_demo</title>
</head>
<body>
    {% if age > 18 %}
      您已满18岁
    {% elif age == 18 %}
      您刚满18岁
    {% else %}
      您未满18岁
    {% endif %}
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

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


if __name__ == '__main__':
    app.run() for循环

Jinjia2中的for循环没有break语句。
filter.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filter_demo</title>
</head>
<body>
    {% for student in students %}
      学生姓名:{{ student.name }},学生年龄:{{ student.age }}
    {% endfor %}
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/filter')
def filte_page():
    students = [
      {'name':'lili', 'age':18},
      {'name':'lucy', 'age':17},
      {'name':'lfiv', 'age':19}
    ]
    return render_template('filter.html', students=students)


if __name__ == '__main__':
    app.run()# 运行项目 模板继承

一个网站中,大部分网页的模块是重复的,比如顶部的导航栏、底部的备案信息等,如果在每个页面中都重复地去写这些代码,会让项目变得臃肿,提高后期维护成本。此时,可以通过模板继承,把一些重复性的代码写在父模板里,子模板继承父模板后,再分别实现自己的代码。
父模板文件base.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
<ul>
    <li><a target="_blank" href="https://www.cnblogs.com/#">首页</a></li>
    <li><a target="_blank" href="https://www.cnblogs.com/#">新闻</a></li>
</ul>
{% block body %}
{% endblock %}
<footer>底部标签</footer>
</body>
</html> child1.html内容如下。
{% extends 'base.html' %}

{% block title %}
    我是子模板
{% endblock %}

{% block body %}
    我是子模板的文字
{% endblock %} app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

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

if __name__ == '__main__':
    app.run() 加载静态文件

static.html内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>static_demo</title>
    <link rel="stylesheet" href="https://www.cnblogs.com/{{ url_for('static', filename='css/style.css') }}">
   
</head>
<body>
    <img src="https://www.cnblogs.com/{{ url_for('static', filename='images/air.jpg') }}" alt="">
</body>
</html> app.py内容如下。
from flask import Flask, render_template

app = Flask(__name__)

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


if __name__ == '__main__':
    app.run() 操作MySQL

Python操作MySQL驱动

Flask要想操作数据库,必须要先安装Python操作MySQL的驱动,在Python中,目前有以下MySQL驱动包:


[*]MySQL-python:也就是MySQLdb,是对C语言操作MySQL数据库的一个简单封装,但只支持Python2。
[*]mysqlclient:是MySQL-python的一个分支,支持Python3并且修复了一些bug,是目前为止执行效率最高的驱动,但是安装的时候容易因为环境问题出错。
[*]pymysql:纯Python实现的驱动,执行效率不如mysqlclient,可以和Python代码无缝衔接。
[*]mysql-connector-python:MySQL官方推出的纯Python连接MySQL驱动,执行效率比pymysql慢。
安装pymysql

pip install pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple 安装Flask-SQLAlchemy

在Flask中,很少会使用pymysql直接写原生SQL语句去操作数据库,更多的是通过SQLAlchemy提供的ORM技术,其类似于操作普通Python对象那样来实现对数据库的增删改查,而Flask-SQLAlchemy是对SQLAlchemy的一个封装,使得在Flask中使用SQLAlchemy更加方便。Flask-SQLAlchemy需要单独安装,因为Flask-SQLAlchemy依赖SQLAlchemy,所以只要安装了Flask-SQLAlchemy,SQLAlchemy会自动安装。
pip install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple SQLAlchemy类似于Jinjia2,是可以独立于Flask而被使用的,完全可以在任何Python程序中被使用。SQLAlchemy官方链接
Flask-SQLAlchemy基本使用

连接MySQL

使用Flask-SQLAlchemy操作数据库之前,需要先创建一个由FLask-SQLAlchemy提供的SQLAlchemy类的对象,在创建这个类的时候,需要传入当前的app,然后要在app.config中设置SQLALCHEMY_DATABASE_URI,来配置数据库的连接。
app.py内容如下。
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
app = Flask(__name__)

HOSTNAME = '127.0.0.1'# 主机名

PORT = 3306# 端口号

USERNAME = 'root'# 连接MySQL的用户名

PASSWORD = '123456'# 连接MySQL的密码

DATABASE = 'db_flask_test'# 在MySQL创建的数据库名称

app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{USERNAME}:                 {PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4'

db = SQLAlchemy(app)

# 在app.config中设置好连接的数据库信息,然后使用SQLAlchemy(app)创建一个db对象,QLAlchemy会自动读取app.config中连接数据库的信息

# 测试是否连接成功
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():
    return render_template('index.html')


if __name__ == '__main__':
    app.run()# 运行项目 注:测试时若报错,提示语句不是可执行的对象,可以使用sqlalchemy.text() 函数对语句进行封装。
ORM模型与表的映射

ORM模型

对象关系映射(Object Relationship Mapping),简称ORM,是一种可以用Python面向对象的方式来操作关系型数据库的技术,具有可以映射到数据库表能力的Python类我们称之为ORM模型。一个ORM模型与数据库中一个表相对应,ORM模型中的每个类属性分别对应表的每个字段,ORM模型的每个实例对象对应表中每条记录。ORM技术提供了面向对象的SQL交互的桥梁,让开发者用面向对象的方式操作数据库,使用ORM模型具有以下优势:


[*]开发效率高:几乎不需要写原生SQL语句,使用纯Python的方式操作数据库。
[*]安全性高:ORM模型底层代码对一些常见的安全问题,比如SQL注入做了防护,比直接使用SQL语句更加安全。
[*]灵活性强:Flask-SQLAlchemy底层支持SQLite、MySQL、Oracle、PostgreSQL等关系型数据库,但针对不同数据库,ORM模型代码几乎一模一样,只需要修改少量代码,即可完成底层数据库的更换。
映射方法

法一——通过db.create_all()映射。

with app.app_context():
    db.create_all()# 将所有的表同步到数据库中 法二——通过flask-migrate映射。

db.create_all()只能识别新增了哪些模型,把新增的模型同步到数据库中,若是模型中字段值改变,它无法识别,这种情况下需要使用flask-migrate。
安装flask-migrate代码如下。
pip install flask-migrate -i https://pypi.tuna.tsinghua.edu.cn/simple flask-migrate三部曲,在命令行中执行如下指令。


[*]flask db init:只执行一次,执行后生成migrations文件夹。
[*]flask db migrate:识别ORM模型的改变,生成迁移脚本。
[*]flask db upgrade:运行迁移脚本,同步到数据库中。
MySQL的增删改查

使用ORM进行增删改查操作,需要先把操作添加到会话中,通过db.session可以获取到会话对象,会话对象只是在内存中,如果要把会话中的操作提交到数据库中,需要调用db.session.commit()操作,如果想要把会话中的操作回滚,则可以通过db.session.rollback()实现。
增加数据

使用ORM创建一条数据,首先需使用ORM模型创建一个对象,然后添加到会话中,再进行commit操作即可。创建对象时,必须要通过关键字参数给字段赋值。
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():
    # 1. 创建ORM对象
    user = User(username="张三", password="123456")
    # sql: insert into user(username, password) values('张三', '123456')
    # 2. 将ORM对象添加到db.session中
    db.session.add(user)
    # 3. 将db.session中的改变同步到数据库中
    db.session.commit()
    return '用户添加成功' 查找数据

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/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='张三')
    for user in users:
      print(user.username)
    return '数据查找成功!' 修改数据

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/update")
def update_user():
    user = User.query.filter_by(username='张三').first()
    user.password = '654321'
    db.session.commit()
    return '数据修改成功' 删除数据

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/delete')
def delete_user():
    # 1. 查找
    user = User.query.get(1)
    # 2. 从db.session中删除
    db.session.delete(user)
    # 3. 将db.session中的修改同步到数据库中
    db.session.commit()
    return '数据删除成功' ORM模型外键与表的关系

关系型数据库中,多个表之间可以建立关系,表关系总体上可以分成三种,分别是:一对一、一对多(多对一)、多对多,表关系的建立是通过数据库层面的外键来实现的,创建外键是通过db.ForeignKey实现的。
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)

    articles = db.relationship('Article', back_populates='author')

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', back_populates='articles')
    # author = db.relationship('User', backref='articles'), backref会自动给User模型添加一个article属性,用来获取文章列表

@app.route("/article/add")
def article_add():
    article1 = Article(title='Flask学习', content="xxxxx")
    article1.author = User.query.get(2)

    article2 = Article(title='Django学习', content='xxxxx')
    article2.author = User.query.get(2)

    # 添加到session中
    db.session.add_all()
    # 同步session中的数据到数据库中
    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 '文章查找成功'
来源:https://www.cnblogs.com/engpj/p/17081086.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 初识Flask