当前位置: 首页 > news >正文

Flask框架 完整实战案例 附代码解读 【3】

        Flask 是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。

        前面已经写过项目从新建运行安装到测试部署的全流程,其中有写Flask框架从新建到部署全流程,但是只有部分代码。本篇主要是实战案例项目的代码运行全流程说明,自己总结的方便查看,也欢迎正在学习的宝子参考,如果有不对的地方,请评论区留言或者私信我,感谢。

目录

一、新建项目以及虚拟环境

二、项目案例代码部分

1.应用工厂

1.1 运行应用

2.数据库

2.1 与数据库建立连接

2.2 创建数据表 

2.3 在应用中注册

2.4 初始化数据库文件

3.蓝图和视图

3.1创建蓝图

3.2新建视图 注册用户

4.模板 

4.1基础布局

4.2 注册模板

4.3 注册一个用户


一、新建项目以及虚拟环境

这里把新建项目以及虚拟环境在写一遍:

这里可以用命令行新建、也可以直接右键新建项目。然后命令行打开文件夹,这里只是举例子,本次项目的项目名称是 flask-tutorial 文件夹。

py -3 -m venv venv    # 创建虚拟环境
venv\Scripts\activate # 激活虚拟环境

新建的项目要新建虚拟环境然后激活虚拟环境,对于已经新建过虚拟环境的直接激活虚拟环境就可以了。

后面下载框架或者项目中需要的包运行应用都是在虚拟环境下进行的。

二、项目案例代码部分

        一个 Flask应用是一个Flask 类的实例,我们在代码的最开始创建一个全局 Flask 实例如何创建全局实例呢?可以在一个函数内部创建一个flask实例,然后把这个应用返回,这个函数被称为应用工厂,因为所有应用的相关配置、注册登录和其他设置都是在这一个函数完成的。

1.应用工厂

        创建一个 flaskr 文件夹,然后新建 __init__.py文件。应用里面的 SECRET_KEY 变量也就是我们上一篇关于项目打包部署的时候生成密钥的值。

        SECRET_KEY 是被 Flask 和扩展用于保证数据安全的。在开发过程中, 为了方便可以设置为 'dev' ,但是在发布的时候应当使用一个随机值来 重载它。

# flaskr/__init__.py 文件代码部分
import os
from flask import Flaskdef create_app(test_config=None):# 创建一个应用实例appapp = Flask(__name__, instance_relative_config=True)app.config.from_mapping(SECRET_KEY='dev',DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),)if test_config is None:# load the instance config, if it exists, when not testingapp.config.from_pyfile('config.py', silent=True)else:# load the test config if passed inapp.config.from_mapping(test_config)# ensure the instance folder existstry:os.makedirs(app.instance_path)except OSError:pass# a simple page that says hello@app.route('/hello')def hello():return 'Hello, World!'return app   #返回应用
1.1 运行应用

前面我们已经设置了应用工厂,所以这里我们应用模块就是flaskr,在设置开发模式,然后运行应用。事实上,后面我们在加入其他代码包括设置或者功能模块也是这样运行的,因为都是在工厂模式里面调用的。

set FLASK_APP=flaskr  #设置应用在哪
> set FLASK_ENV=development  #设置开发模式
> flask run  #运行应用
2.数据库

 Python 内置了 SQLite 数据库支持,项目也是使SQLite来存储数据的,相应的模块为sqlite3.

        使用 SQLite 的便利性在于不需要单独配置一个数据库服务器,并且 Python 提供了 内置支持。小应用没有问题,但是大应用可能就需要考虑换成别的数据库了。

2.1 与数据库建立连接

新建flaskr/db.py文件:

# flaskr/db.py 文件代码import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontextdef get_db():if 'db' not in g:#建立一个数据库连接 该连接指向配置中的 DATABASE 指定的文件g.db = sqlite3.connect(current_app.config['DATABASE'],detect_types=sqlite3.PARSE_DECLTYPES)#告诉连接返回类似于字典的行,这样可以通过列名称来操作 数据g.db.row_factory = sqlite3.Rowreturn g.dbdef close_db(e=None):db = g.pop('db', None)# 如果连接已建立就关闭连接if db is not None:db.close()

在上面的代码中 是一个特殊对象,独立于每一个请求,用于存储请求过程中可能多个函数都会用到的数据,把连接储存起来可以多次使用。

 current_app 是另一个特殊对象,该对象指向处理请求的 Flask 应用,就是使用这个特殊对象,get_db 函数才会被调用。

2.2 创建数据表 

现在要创建一个sql文件,用于生成应用中用到的数据表的sql语句,我们用数据表user来存储用户信息,用数据表名posts来存储博客数据。

新建文件flaskr/schema.sql :

DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT UNIQUE NOT NULL,password TEXT NOT NULL
);CREATE TABLE post (id INTEGER PRIMARY KEY AUTOINCREMENT,author_id INTEGER NOT NULL,created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,title TEXT NOT NULL,body TEXT NOT NULL,FOREIGN KEY (author_id) REFERENCES user (id)
);

sql文件写好了,我们需要调用这个文件执行sql语句,前面我们已经db.py文件中已经连接数据,我们继续在db.py文件中写入python函数用来执行sql文件:

flaskr/db.py文件中新增执行sql文件的函数:

def init_db():db = get_db()with current_app.open_resource('schema.sql') as f:  #打开sql文件db.executescript(f.read().decode('utf8')) #执行sql文件命令# #定义一个名为 init-db 命令行,它调用 init_db 函数,并为用户显示一个成功的消息
@click.command('init-db') 
@with_appcontext
def init_db_command():"""Clear the existing data and create new tables."""init_db()click.echo('Initialized the database.')
2.3 在应用中注册

close_db 和 init_db_command 函数需要在应用实例中注册,否则无法使用,我们写一个函数,把应用作为参数,在函数中进行注册。

flaskr/db.py新增代码:

def init_app(app):app.teardown_appcontext(close_db) #告诉 Flask 在返回响应后进行清理的时候调用此函数app.cli.add_command(init_db_command) #添加一个新的 可以与 flask 一起工作的命令。

然后在工厂中调用init_app()函数.在工厂中导入并调用这个函数。在工厂函数中把新的代码放到 函数的尾部,返回应用代码的前面。

flaskr/__init__.py文件代码新增:

def create_app():app = ...# existing code omittedfrom . import dbdb.init_app(app)return app
2.4 初始化数据库文件

我们现在已经把应用在函数中进行注册了,现在可以运行应用了,还是和上面一样设置下应用模块然后flask run 运行:

set FLASK_APP=flaskr  #设置应用在哪
set FLASK_ENV=development  #设置开发模式
flask run  #运行应用
flask init-db
#Initialized the database.

现在会有一个 flaskr.sqlite 文件出现在项目所在文件夹的 instance 文件夹 中。

3.蓝图和视图

试图和蓝图不一样,简单的讲视图是响应请求的函数,返回数据。Blueprint蓝图是组织一组相关视图和其他代码的方式。把视图和代码注册到蓝图,然后在工厂函数中 把蓝图注册到应用。

3.1创建蓝图

Flaskr 有两个蓝图,一个用于认证功能,另一个用于博客帖子管理。每个蓝图的代码 都在一个单独的模块中。使用博客首先需要认证,因此我们先写认证蓝图。

新建文件flaskr/auth.py 代码如下:

import functoolsfrom flask import (Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hashfrom flaskr.db import get_dbbp = Blueprint('auth', __name__, url_prefix='/auth')

这里创建了一个名称为 'auth' 的 Blueprint 。和应用对象一样, 蓝图需要知道是在哪里定义的,因此把 __name__ 作为函数的第二个参数。 url_prefix 会添加到所有与该蓝图关联的 URL 前面。

使用 app.register_blueprint 导入并注册 蓝图。新的代码放在工厂函数的尾部返回应用之前。

flaskr/__init__.py文件新增代码:

def create_app():app = ...# existing code omittedfrom . import authapp.register_blueprint(auth.bp)return app

认证蓝图将包括注册新用户、登录和注销视图。

3.2新建视图 注册用户

在flaskr/auth.py文件中新增视图代码:

#bp.route关联了 URL /register 和 register 视图函数
@bp.route('/register', methods=('GET', 'POST')) 
def register():if request.method == 'POST':username = request.form['username']password = request.form['password']db = get_db()error = Noneif not username:error = 'Username is required.'elif not password:error = 'Password is required.'elif db.execute('SELECT id FROM user WHERE username = ?', (username,)).fetchone() is not None:error = 'User {} is already registered.'.format(username)if error is None:# db.execute使用了带有 ? 占位符 的 SQL 查询语db.execute('INSERT INTO user (username, password) VALUES (?, ?)',(username, generate_password_hash(password)))db.commit()return redirect(url_for('auth.login'))flash(error)return render_template('auth/register.html')

占位符可以代替后面的元组参数中相应的值。使用占位符的 好处是会自动帮你转义输入值,以抵御 SQL 注入攻击 。

 fetchone() 根据查询返回一个记录行。 如果查询没有结果,则返回 None 。视图中如果查询到用户已存在则提示用户已存在,如果用户不存在就向数据插入一条用户信息的数据,然后提交数据库,跳转到登录页面。当用户最初访问视图会打开一个注册页面的表单,render_template会渲染一个包含 HTML 的模板。

后面登录、注销其实逻辑都是一样的。

4.模板 

模板文件其实就是HTML。会储存在 flaskr 包内的 templates 文件夹内。模板是包含静态数据和动态数据占位符的文件。模板使用指定的数据生成最终的文档。Flask 使用 Jinja 模板库来渲染模板。

4.1基础布局

应用中的每一个页面主体不同,但是基本布局是相同的。每个模板会 扩展 同一个 基础模板并重载相应的小节,而不是重写整个 HTML 结构。

新建flaskr/templates/base.html文件 :

<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav><h1>Flaskr</h1><ul>{% if g.user %}<li><span>{{ g.user['username'] }}</span><li><a href="{{ url_for('auth.logout') }}">Log Out</a>{% else %}<li><a href="{{ url_for('auth.register') }}">Register</a><li><a href="{{ url_for('auth.login') }}">Log In</a>{% endif %}</ul>
</nav>
<section class="content"><header>{% block header %}{% endblock %}</header>{% for message in get_flashed_messages() %}<div class="flash">{{ message }}</div>{% endfor %}{% block content %}{% endblock %}
</section>

在模板中 g 和 url_for() 可直接使用,g.user()显示用户状态,用户名或者注销显示注册和登录连接,url_for可用于生成视图的 URL ,而不用手动来指定。

模板中定义三个块,这些块会被其他模板重载。

  1. {% block title %} 会改变显示在浏览器标签和窗口中的标题。

  2. {% block header %} 类似于 title ,但是会改变页面的标题。

  3. {% block content %} 是每个页面的具体内容,如登录表单或者博客帖子。

其他模板直接放在 templates 文件夹内。为了更好地管理文件,属于某个蓝图 的模板会被放在与蓝图同名的文件夹内。

4.2 注册模板

flaskr/templates/auth/register.html

{% extends 'base.html' %}{% block header %}<h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}{% block content %}<form method="post"><label for="username">Username</label><input name="username" id="username" required><label for="password">Password</label><input type="password" name="password" id="password" required><input type="submit" value="Register"></form>
{% endblock %}

{% extends 'base.html' %} 告诉 Jinja 这个模板基于基础模板,并且需要替换 相应的块。所有替换的内容必须位于 {% block %} 标签之内。

一个实用的模式是把 {% block title %} 放在 {% block header %} 内部。 这里不但可以设置 title 块,还可以把其值作为 header 块的内容, 一举两得。

静态文件 除了 CSS ,其他类型的静态文件可以是 JavaScript 函数文件或者 logo 图片。它们 都放置于 flaskr/static 文件夹中,并使用 url_for('static', filename='...') 引用。基础模板中有用到引入样式文件。

4.3 注册一个用户

现在浏览器输入http://127.0.0.1:5000/auth/register 可以注册一个用户了。请确定服务器还在运行

博客蓝图和视图逻辑都类似的。

项目代码部分完成后,然后项目可安装化和部署前面一篇项目部署全流程都总结过啦!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【CSS】如何写渐变色文字并且有打光效果
  • OceanBase V4.2解析:如何用迭代器 Generator快速生成任意数据
  • DS18B20温度传感器详解(STM32)
  • MySQL基础学习:MySQL主从复制如何实现
  • 在HarmonyOS中灵活运用Video组件实现视频播放
  • Golang | Leetcode Golang题解之第385题迷你语法分析器
  • Level3 — PART 4 机器学习算法 — 集成学习
  • RK3568 Android 11 蓝牙BluetoothA2dpSink 获取用于生成频谱的PCM
  • 测试 UDP 端口可达性的方法
  • 学习笔记--Docker
  • Android实现自定义方向盘-7livedata,viewmodel相关问题
  • 编译FFmpeg动态库
  • 传统CV算法——图像特征算法之角点检测算法
  • 比亚迪方程豹携手华为乾崑智驾,加速中国智驾技术向前
  • 【粒子群算法PSO】基本原理及多种改进方法
  • ----------
  • 深入了解以太坊
  • 【剑指offer】让抽象问题具体化
  • Create React App 使用
  • ECMAScript6(0):ES6简明参考手册
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Java方法详解
  • Rancher如何对接Ceph-RBD块存储
  • React系列之 Redux 架构模式
  • 从输入URL到页面加载发生了什么
  • 关于extract.autodesk.io的一些说明
  • 排序算法之--选择排序
  • 前端_面试
  • 强力优化Rancher k8s中国区的使用体验
  • 使用 Docker 部署 Spring Boot项目
  • 听说你叫Java(二)–Servlet请求
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 《天龙八部3D》Unity技术方案揭秘
  • ​人工智能书单(数学基础篇)
  • #100天计划# 2013年9月29日
  • #14vue3生成表单并跳转到外部地址的方式
  • (09)Hive——CTE 公共表达式
  • (1) caustics\
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (第27天)Oracle 数据泵转换分区表
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二十六)Java 数据结构
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (力扣)循环队列的实现与详解(C语言)
  • (论文阅读11/100)Fast R-CNN
  • (四)汇编语言——简单程序
  • (一) storm的集群安装与配置
  • (转) ns2/nam与nam实现相关的文件
  • (转)3D模板阴影原理
  • ***测试-HTTP方法
  • .NET 动态调用WebService + WSE + UsernameToken
  • .NET单元测试
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)