笔记1-Flask网站开发.md 59 KB

Flask + MySQL网站开发

Flask基础知识

Flask教程: https://www.w3cschool.cn/flask/flask_overview.html

Flask安装

pip install Flask

image-20221120232533820

Flask 一个最小的应用

打开Pycharm软件, 新建一个Python项目, 命名为FlaskDemo,选择Ptyhon环境为Python 3.9.

image-20221126042334677

在main.py代码文件中编写如下代码:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

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

运行程序, 能够看到运行成功, 提示Flask程序已经运行在http://127.0.0.1: 5000端口, 结果如下:

image-20221126042623049

直接点击上图中的http://127.0.0.1: 5000链接, 或者在浏览器的地址栏中输入该地址, 即可访问网站,看到Hello World页面.

image-20221126042933223

程序解释:

(1) "from flask import Flask" 导入了 Flask 类。这个类的实例将会是一个WSGI 应用程序。

(2) "app = Flask(__ name __ )" 创建一个该类的实例,第一个参数是应用模块或者包的名称。 Flask构造函数使用当前模块(__name __)的名称作为参数。如果你使用单一的模块(如本例),你应该使用 __ name __ ,因为模块 的名称将会因其作为单独应用启动还是作为模块导入而有不同( 也即是 'main' 或实际的导入名)。这是必须的,这样 Flask 才知道到哪去找模板、静态文件等等。

(3) 使用 route() 装饰器告诉 Flask 什么样 的URL 能触发我们的函数。这个函数的名字也在生成 URL 时被特定的函数采用,这个函数返回想要显示在用户浏览器中的信息。

Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数。

app.route(rule, options)
  • rule 参数表示与该函数的URL绑定。
  • options 是要转发给基础Rule对象的参数列表。

在上面的示例中,'/ ' URL与hello_world()函数绑定。

因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。

(4) Flask类的run()方法在本地开发服务器上运行应用程序, 让应用运行在本地服务器上。其中 if name == 'main': 确保服务器只会在该脚本被 Python 解释器直接执行的时候才会运行,而不是作为模块导入的时候。

app.run(host, port, debug, options)

所有参数都是可选的

序号 参数与描述
1 host 要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用
2 port 默认值为5000
3 debug 默认为false。 如果设置为true,则提供调试信息
4 options 要转发到底层的Werkzeug服务器。

欲关闭服务器,按 Ctrl+C。

(5) 外部可访问的服务器

如果你运行了这个服务器,你会发现它只能从你自己的计算机上访问,网络 中其它任何的地方都不能访问。在调试模式下,用户可以在你的计算机上执 行任意 Python 代码。因此,这个行为是默认的。

如果你禁用了 debug 或信任你所在网络的用户,你可以简单修改调用 run() 的方法使你的服务器公开可用,如下:

app.run(host='0.0.0.0')

这会让操作系统监听所有公网 IP。

Flask 调试模式

虽然 run() 方法适用于启动本地的开发服务器,但是 你每次修改代码后都要手动重启它。这样并不够优雅,而且 Flask 可以做到更 好。如果你启用了调试支持,服务器会在代码修改后自动重新载入,并在发生 错误时提供一个相当有用的调试器。

有两种途径来启用调试模式。一种是直接在应用对象上设置:

app.debug = True
app.run()

另一种是作为 run 方法的一个参数传入:

app.run(debug=True)

两种方法的效果完全相同。

Flask 路由(页面路由)

现代 Web 应用的 URL 十分优雅,易于人们辨识记忆,这一点对于那些面向使 用低速网络连接移动设备访问的应用特别有用。如果可以不访问索引页,而是 直接访问想要的那个页面,他们多半会笑逐颜开而再度光顾。

如上所见, route() 装饰器把一个函数绑定到对应的 URL 上。

例如: 在main.py文件中编写以下函数, 实现flask的路由(页面跳转)

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/page2')
def gopage2():
    return '你好'

在这里,URL '/page2' 规则绑定到gopage2()**函数。

因此,如果用户访问**http://localhost:5000/page2

gopage2()函数的输出将在浏览器中呈现。

application对象的add_url_rule()函数也可用于将URL与函数绑定,如上例所示,使用route()

装饰器的目的也由以下表示:

def gopage2():
   return '你好'
app.add_url_rule('/', 'page2', gopage2)

image-20221126050322597

重新运行程序, 访问http://127.0.0.1:500/page2, 即可看到page2页面以及内容.

image-20221126044147717

如何通过路由链接到一个已存在的页面?

使用如下代码: 具体见"Falsk HTTP方法"小节的内容.

return render_template("xxx.html")

Flask 变量规则(参数传递)

通过向规则参数添加变量部分,可以动态构建URL。

此变量部分标记为

它作为关键字参数传递给与规则相关联的函数。

在以下示例中,route()装饰器的规则参数包含附加到URL '/hello'

因此,如果在浏览器中输入http://localhost:5000/hello/sysu作为URL,则'sysu'将作为参数提供给 hello_name()函数。

from flask import Flask
app = Flask(__name__)

@app.route('/hello/<name>')
def hello_name(name):
   return '你好, %s!' % name

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

image-20221126050919462

接下来,打开浏览器并输入URL http:// localhost:5000/hello/sysu。

以下输出将显示在浏览器中:

image-20221126050808386

除了默认字符串变量部分之外,还可以使用以下转换器构建规则:

序号 转换器 描述
1 int 接受整数
2 float 对于浮点值
3 **path ** 接受用作目录分隔符的斜杠

在下面的代码中,使用了所有这些构造函数:

from flask import Flask
app = Flask(__name__)

@app.route('/blog/<int:postID>')
def show_blog(postID):
   return 'Blog Number %d' % postID

@app.route('/rev/<float:revNo>')
def revision(revNo):
   return 'Revision Number %f' % revNo

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

从Python Shell运行上面的代码。访问浏览器中的URL **http://localhost:5000/blog/32。

给定的数字用作show_blog()函数的参数。浏览器显示以下输出:

image-20221126051048005

在浏览器中输入此URL - http://localhost:5000/rev/3.5

revision()函数将浮点数作为参数。以下结果显示在浏览器窗口中:

image-20221126051122351

Flask的URL规则基于Werkzeug的路由模块。

这确保形成的URL是唯一的,并且基于Apache规定的先例。

考虑以下脚本中定义的规则:

from flask import Flask
app = Flask(__name__)

@app.route('/flask')
def hello_flask():
   return 'Hello Flask'

@app.route('/python/')
def hello_python():
   return 'Hello Python'

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

这两个规则看起来类似,但在第二个规则中,使用斜杠(/)。因此,它成为一个规范的URL。

因此,使用 /python/python/返回相同的输出。

image-20221126051347803 image-20221126051335208

但是,如果是第一个规则,/flask/ URL会产生“404 Not Found”页面。

image-20221126051244677 image-20221126051301045

Flask URL构建(多页面跳转)

url_for()函数对于动态构建特定函数的URL非常有用。

url_for()函数接受函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应于URL的变量部分。

以下脚本演示了如何使用url_for()函数:

from flask import Flask, redirect, url_for
app = Flask(__name__)

@app.route('/admin')
def hello_admin():
   return 'Hello Admin'

@app.route('/guest/<guest>')
def hello_guest(guest):
   return 'Hello %s as Guest' % guest

@app.route('/user/<name>')
def hello_user(name):
   if name =='admin':
      return redirect(url_for('hello_admin'))
   else:
      return redirect(url_for('hello_guest', guest = name))

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

image-20221126052148990

说明: 以上功能需要用到Flask库中的redirect和 url_for函数, 因此需要先import进来.

上述脚本有一个函数hello_user(name),它接受来自URL的参数的值。

hello_user()函数检查接收的参数是否与'admin'匹配。

如果匹配,则使用url_for()将应用程序重定向到hello_admin()函数,否则重定向到将接收的参数作为guest参数传递给它的hello_guest()函数。

保存上面的代码并从Python shell运行。

打开浏览器并输入URL - http://localhost:5000/user/admin

浏览器中的应用程序响应是:

image-20221126052235405

在浏览器中输入以下URL - http://localhost:5000/user/cc

应用程序响应现在更改为:

image-20221126052256861

如果不传参数, 则会提示找不到页面. 因为函数中没有编写此类情况的处理.

image-20221126052224596

Flask 重定向

Flask类有一个redirect()函数。调用时,它返回一个响应对象,并将用户重定向到具有指定状态代码的另一个目标位置。

redirect()函数的原型如下:

Flask.redirect(location, statuscode, response)

在上述函数中:

  • location参数是应该重定向响应的URL。
  • statuscode发送到浏览器标头,默认为302。
  • response参数用于实例化响应。

Flask HTTP方法(页面间传值方式)

Http协议是万维网中数据通信的基础。在该协议中定义了从指定URL检索数据的不同方法。

下表总结了不同的http方法:

序号 方法与描述
1 GET以未加密的形式将数据发送到服务器。最常见的方法。
2 HEAD和GET方法相同,但没有响应体。
3 POST用于将HTML表单数据发送到服务器。POST方法接收的数据不由服务器缓存。
4 PUT用上传的内容替换目标资源的所有当前表示。
5 DELETE 删除由URL给出的目标资源的所有当前表示。

默认情况下,Flask路由响应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项。

为了演示在URL路由中使用POST方法,首先让我们创建一个HTML表单,并使用POST方法将表单数据发送到URL。

将以下脚本另存为login.html

<html>
   <body>
      <form action = "/login" method = "post">
         <p>Enter Name:</p>
         <p><input type = "text" name = "nm" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
   </body>
</html>

新建一个python文件,命名为demo2.py, 输入以下代码:

from flask import Flask, redirect, url_for, request, render_template

app = Flask(__name__)

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

@app.route('/success/<name>')
def success(name):
    return 'welcome %s' % name

@app.route('/login',methods = ['POST', 'GET'])
def login():
   if request.method == 'POST':
      print(1)
      user = request.form['nm']
      return redirect(url_for('success',name = user))
   else:
      print(2)
      user = request.args.get('nm')
      return redirect(url_for('success',name = user))

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

注意, 由于端口号5000已经被刚才的main.py程序使用了, 因此, demo2.py程序可以使用一个新的端口号,例如:5001.

开发服务器开始运行后,在浏览器中打开login.html,在文本字段中输入name,然后单击提交

image-20221126053747087image-20221126053935292

注意,此时需要打开html文件所在的文件夹, 直接双击该login.html文件才能访问页面.

如果直接在地址栏中输入:127.0.0.1:5001,则会提出Internal Server Error错误, 错误原因是jinja2.exception.TemplateNotFound: login.html, 即, 没有将login.html没有设为模板页.

如果直接在地址栏中输入: 127.0.0.1:5001/login.html, 则会提示找不到该页面.

image-20221126053802163 image-20221126054657118image-20221126053717276

表单数据将POST到表单标签的action子句中的URL。

http://localhost/login映射到login()函数。由于服务器通过POST方法接收数据,因此通过以下步骤获得从表单数据获得的“nm”参数的值:

user = request.form['nm']

它作为变量部分传递给'/success' URL。浏览器在窗口中显示welcome 消息。

image-20221126054429802

login.html中将方法参数更改为'GET',然后在浏览器中再次打开它。服务器上接收的数据是通过GET方法获得的。通过以下的步骤获得'nm'参数的值:

User = request.args.get('nm')

这里,args是包含表单参数对及其对应值对的列表的字典对象。与'nm'参数对应的值将像之前一样传递到'/ success' URL。

image-20221126054529401

Flask进阶

Flask 模板(静态模板页面+动态数据渲染)

在前面的实例中,视图函数的主要作用是生成请求的响应,这是最简单的请求。

视图函数有两个作用:

  • 处理业务逻辑
  • 返回响应内容

在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本.

  • 模板其实是一个包含响应文本的文件,其中用占位符(变量)表示动态部分,告诉模板引擎其具体的值需要从使用的数据中获取
  • 使用真实值替换变量,再返回最终得到的字符串,这个过程称为'渲染'
  • Flask 是使用 Jinja2 这个模板引擎来渲染模板

使用模板的好处

  • 视图函数只负责业务逻辑和数据处理(业务逻辑方面)
  • 而模板则取到视图函数的数据结果进行展示(视图展示方面)
  • 代码结构清晰,耦合度低

(1) 模板基本使用

在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件 html 文件 hello.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我的模板html内容
</body>
</html>

image-20221126055724039

创建一个demo3.py文件,在route视图函数中, 将该模板内容进行渲染返回

from flask import Flask, render_template

app = Flask(__name__)

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

运行程序, 在浏览器中访问http://127.0.0.1:5000,即可跳转到hello.html页面

image-20221126060540371

(2)模板变量

代码中传入字符串,列表,字典到模板中

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    # 往模板中传入的数据
    my_str = 'Hello Word'
    my_int = 10
    my_array = [3, 4, 2, 1, 7, 9]
    my_dict = {
        'name': 'xiaoming',
        'age': 18
    }
    return render_template('hello.html',
                           my_str=my_str,
                           my_int=my_int,
                           my_array=my_array,
                           my_dict=my_dict
                           )

在HTML模板中,编写相应的变量。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  我的模板html内容
  <br />{{ my_str }}
  <br />{{ my_int }}
  <br />{{ my_array }}
  <br />{{ my_dict }}
</body>
</html>

运行效果

image-20221126060834425

(3)示例代码2 :

HTML模板页面脚本,继续编写如下变量,主要是体验list数据元素和字典数据元素的读取。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我的模板html内容
  <br />{{ my_str }}
  <br />{{ my_int }}
  <br />{{ my_array }}
  <br />{{ my_dict }}
 <hr>
  <h2>模板的list数据获取</h2>
  <hr>
  {{ my_array[0] }}
  <br>
  {{ my_array.1 }}
  <hr>
  <h2>字典数据获取</h2>
  <hr>
  {{ my_dict['name'] }}
  <br>
  {{ my_dict.age }}
  <hr>
  <h2>算术运算</h2>
  <br>
  {{ my_array.0 + 10 }}
  <br>
  {{ my_array[0] + my_array.1 }}
</body>
</html>

不需要修改demo3.py文件中的代码,直接重新运行程序,访问页面,运行结果如下。

image-20221126061337707

Flask 静态文件(调用Javascript)

Web应用程序通常需要静态文件,例如javascript文件或支持网页显示的CSS文件。

通常,配置Web服务器并为您提供这些服务,但在开发过程中,这些文件是从您的包或模块旁边的*static*文件夹中提供,它将在应用程序的/static中提供。

特殊端点'static'用于生成静态文件的URL。

在下面的示例中,在index.html中的HTML按钮的OnClick事件上调用hello.js中定义的javascript函数,该函数在Flask应用程序的“/”URL上呈现。

首先,创建一个demo4.py文件,编写如下代码。

from flask import Flask, render_template
app = Flask(__name__)

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

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

接着,在templates 文件夹中创建一个index.html文件,编写如下HTML脚本:

<html>
   <head>
      <script type = "text/javascript" 
         src = "{{ url_for('static', filename = 'hello.js') }}" ></script>
   </head>
   
   <body>
      <input type = "button" onclick = "sayHello()" value = "Say Hello" />
   </body>
</html>

在index.html中的HTML按钮的OnClick事件上调用hello.js中定义的javascript函数。

第三,创建一个static文件夹,在static文件夹中创建一个hello.js文件,编写sayHello()函数。

function sayHello() {
   alert("Hello World")
}

重新运行程序,运行效果如下:

image-20221126061956548

点击“Say Hello”按钮,调用JavaScript函数,运行JS脚本功能。

image-20221126062101498

Flask 将表单数据发送到模板

我们已经看到,可以在 URL 规则中指定 http 方法。触发函数接收的 Form 数据可以以字典对象的形式收集它并将其转发到模板以在相应的网页上呈现它。

(1)Flask Request对象

来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应该从Flask模块导入。

Request对象的重要属性如下所列:

  • Form - 它是一个字典对象,包含表单参数及其值的键和值对。
  • args - 解析查询字符串的内容,它是问号(?)之后的URL的一部分。
  • Cookies - 保存Cookie名称和值的字典对象。
  • files - 与上传文件有关的数据。
  • method - 当前请求方法。

(2)示例演示

在以下示例中,'/' URL 会呈现具有表单的网页(student.html)。

填入的数据会发布到触发 result() 函数的 '/result' URL

result() 函数收集字典对象中的 request.form 中存在的表单数据,并将其发送给 result.html

该模板动态呈现表单数据的 HTML 表格。

下面给出的是应用程序的 Python 代码:

创建一个demo5.py文件,编写如下代码:

from flask import Flask, render_template, request
app = Flask(__name__)

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

@app.route('/result',methods = ['POST', 'GET'])
def result():
   if request.method == 'POST':
      result = request.form
      return render_template("result.html",result = result)

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

image-20221126064904320

接着,在templates文件夹下创建一个student.html页面文件,编写如下Form表单脚本。

<html>
<head>
    <title>Student Register</title>
</head>
<body>
<form action="http://localhost:5000/result" method="POST">
     <p>Name <input type = "text" name = "Name" /></p>
     <p>Physics <input type = "text" name = "Physics" /></p>
     <p>Chemistry <input type = "text" name = "chemistry" /></p>
     <p>Maths <input type ="text" name = "Mathematics" /></p>
     <p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>

image-20221126064934672

然后,在templates文件夹下创建一个result.html页面文件,编写如下模板代码:

<html>
<head>
    <title>Student Information</title>
</head>
<body>
  <table border = 1>
     {% for key, value in result.items() %}
    <tr>
       <th> {{ key }} </th>
       <td> {{ value }}</td>
    </tr>
 {% endfor %}
</table>
</body>
</html>

image-20221126065006719

运行程序,在浏览器中输入 URL http://localhost:5000/

image-20221126064509554 image-20221126064603853

当点击提交按钮时,表单数据以 HTML 表格的形式呈现在 result.html 上。可以看到结果被遍历显示在页面的表格中。

image-20221126064733344

Flask Session会话(登录判断)

会话是客户端登录到服务器并注销服务器的时间间隔,需要在该会话中保存的数据会存储在服务器上的临时目录中。

为每个客户端的会话分配会话IDSession(会话)数据存储在服务器上。服务器以加密方式对其进行签名。对于此加密,Flask应用程序需要一个定义的SECRET_KEY

Session对象也是一个字典对象,包含会话变量和关联值的键值对。

例如,要设置一个'username'会话变量,请使用以下语句:

Session['username'] = 'admin'

要释放会话变量,请使用pop()方法。

session.pop('username', None)

创建一个demo6_session.py文件,编写以下代码,作为Flask中的会话工作的简单演示。

首先,创建一个Falsk对象,定义一个密钥,密钥内容自己写,可以是任意随机的字符串。

编写route('/')函数,URL '/'只是提示用户登录,因为此时还没有设置会话变量'username'的值。

from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj'

@app.route('/')
def index():
    if 'username' in session:
        username = session['username']
        return '登录用户名是:' + username + '<br>' + \
                 "<b><a href = '/logout'>点击这里注销</a></b>"
    return "您暂未登录, <br><a href = '/login'></b>" + \
         "点击这里登录</b></a>"

当用户浏览到“/login”login()视图函数时,因为它是通过GET方法调用的,所以将打开一个登录表单。

表单发送回'/login',现在会话变量已设置。应用程序重定向到'/'。此时会话变量'username'被找到。

@app.route('/login', methods = ['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''<form action = "" method = "post">
      <p><input type="text" name="username"/></p>
      <p><input type="submit" value ="登录"/></p>
   </form> '''

应用程序还包含一个logout()视图函数,它会弹出'username'会话变量。因此,'/' URL再次显示开始页面。

@app.route('/logout')
def logout():
   # remove the username from the session if it is there
   session.pop('username', None)
   return redirect(url_for('index'))

完整代码如下所示:

from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj'

@app.route('/')
def index():
    if 'username' in session:
        username = session['username']
        return '登录用户名是:' + username + '<br>' + \
                 "<b><a href = '/logout'>点击这里注销</a></b>"
    return "您暂未登录, <br><a href = '/login'></b>" + \
         "点击这里登录</b></a>"

@app.route('/login', methods = ['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return ''' <form action = "" method = "post">
      <p><input type="text" name="username"/></p>
      <p><input type="submit" value ="登录"/></p>
   </form>'''

@app.route('/logout')
def logout():
   # remove the username from the session if it is there
   session.pop('username', None)
   return redirect(url_for('index'))

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

image-20221126070625456

运行程序,效果如下。

image-20221126070112071

点击“点击此处登录”链接。链接将被定向到另一个屏幕。键入“admin”。

image-20221126070132041image-20221126070143531

屏幕会显示消息“ 登录用户名是:admin ”。

点击”点击这里注销“链接,则会删除Session变量,并跳转到login页面。

image-20221126070158809image-20221126070209909

Flask 消息闪现

Flask 提供了一个非常简单的方法来使用闪现系统向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息,并且在下次(且仅在下一次中)请求时访问它,这通常与布局模板结合使用以公开信息。

在 Flask Web 应用程序中生成这样的信息性消息很容易。Flask 框架的闪现系统可以在一个视图中创建消息,并在名为 next 的视图函数中呈现它。

Flask 模块包含 flash() 方法。它将消息传递给下一个请求,该请求通常是一个模板。

flash(message, category)

其中,

  • message 参数是要闪现的实际消息。
  • category 参数是可选的。它可以是“error”,“info”或“warning”。

为了从会话中删除消息,模板调用 get_flashed_messages()

get_flashed_messages(with_categories, category_filter)

两个参数都是可选的。如果接收到的消息具有类别,则第一个参数是元组。第二个参数仅用于显示特定消息。

以下闪现在模板中接收消息。

{% with messages = get_flashed_messages() %}
   {% if messages %}
      {% for message in messages %}
         {{ message }}
      {% endfor %}
   {% endif %}
{% endwith %}

示例

创建一个demo7_flash.py文件,编写如下代码。演示Flask中的闪现机制。

'/' URL 显示登录页面的链接,没有消息闪现。

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

接着编写/login函数,该链接会将用户引导到'/login' URL,该 URL 显示登录表单。

提交时,login() 视图函数验证用户名和密码,并相应闪现 'success' 消息或创建 'error' 变量。

@app.route('/login', methods = ['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != 'admin' or request.form['password'] != 'admin':
           error = 'Invalid username or password. Please try again!'
       else:
           flash('You were successfully logged in')
           return redirect(url_for('index'))
    return render_template('login.html', error = error)

如果出现错误,则会重新显示登录模板,并显示错误消息。

下面给出了 Flask 消息闪现示例的完整代码:

(1)demo7_flash.py

from flask import Flask, flash, redirect, render_template, request, url_for
app = Flask(__name__)
app.secret_key = 'random string'

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

@app.route('/login', methods = ['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != 'admin' or request.form['password'] != 'admin':
            error = 'Invalid username or password. Please try again!'
        else:
            flash('You were successfully logged in')
            return redirect(url_for('index'))
    return render_template('login7.html', error = error)

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

image-20221126074431124

(2)login7.html

接着编写login.html文件,在页面中编写一个Form表单,编写username和password的表单控件,提交路径为“/login”,这会将表单数据传入demo7_flask.py文件中的/login函数。编写error模板代码,将显示flask的消息。

<html>
<head>
    <title>Login</title>
</head>
<body>
    <form method = "post" action = "/login">
        <table>
            <tr>
                <td>Username</td>
                <td><input type = 'username' name = 'username'></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type = 'password' name = 'password'></td>
            </tr>
            <tr>
                <td><input type = "submit" value = "Submit"></td>
            </tr>
        </table>
    </form>
    {% if error %}
        <p><strong>Error</strong>: {{ error }}</p>
    {% endif %}
</body>
</html>

image-20221126074522343

(3) Index7.html

另一方面,如果登录成功,则会在索引模板上刷新成功消息。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
    {% with messages = get_flashed_messages() %}
         {% if messages %}
               {% for message in messages %}
                    <p>{{ message }}</p>
               {% endfor %}
         {% endif %}
    {% endwith %}
<h3>Welcome!</h3>
<a href = "{{ url_for('login') }}">login</a>
</body>
</html>

image-20221126074555323

运行程序,在浏览器中访问http://127.0.0.1:5002,运行界面如下:

image-20221126074129900

点击“login”链接,您将被定向到登录页面。输入用户名和密码。

image-20221126074141814image-20221126074151415

当输入的用户名不为"admin"、密码也不为"admin"时(admin是自己在程序中写的,可以更换),在当前页面直接示意用户名或者密码错误。

image-20221126074238983

当用户名或者密码输入成"admin"时,再点击登录。将跳转到index7.html页面中,并显示一条消息“您已成功登录”。

image-20221126074314927

Flask 文件上传

在 Flask 中处理文件上传非常简单。它需要一个 HTML 表单,其 enctype 属性设置为“multipart/form-data”,将文件发布到 URL。

URL 处理程序从 request.files[] 对象中提取文件,并将其保存到所需的位置。

每个上传的文件首先会保存在服务器上的临时位置,然后将其实际保存到它的最终位置。

目标文件的名称可以是硬编码的,也可以从 request.files[file]对象的filename属性中获取。

但是,建议使用 secure_filename() 函数获取它的安全版本。

可以在 Flask 对象的配置设置中定义默认上传文件夹的路径和上传文件的最大大小。

app.config['UPLOAD_FOLDER'] 定义上传文件夹的路径

app.config['MAX_CONTENT_LENGTH'] 指定要上传的文件的最大大小(以字节为单位)

示例: 以下代码具有 '/upload'URL 规则,该规则在 templates 文件夹中显示'upload.html',以及 '/upload-file'URL 规则,用于调用 uploader()函数处理上传过程。

upload.html文件

在templates文件夹中创建一个upload.html网页文件, 在里面编写一个表单, 包含一个文件选择器按钮和一个提交按钮。

<html>
<head>
  <title>File Upload</title>
</head>
<body>
    <form action="/uploader" method="POST" enctype="multipart/form-data">
        <input type="file" name="file"  />
        <input type="submit" value="提交" />
    </form>
</body>
</html>

image-20221126163655697

创建一个demo8_uploadfile.py文件, 编写如下代码:

表单的post方法调用'/upload_file' URL。

底层函数 uploader() 执行保存操作。

from flask import Flask, render_template, request
    from werkzeug.utils import secure_filename
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'upload/'

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

@app.route('/uploader',methods=['GET','POST'])
def uploader():
    if request.method == 'POST':
        f = request.files['file']        
        print(request.files)        
        f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))        
        return 'file uploaded successfully'    
    else:        
        return render_template('upload.html')
    
if __name__ == '__main__':
   app.run(port=5005)

接着,在项目根目录下创建一个upload文件夹, 用于存放要上传的文件.

注意:app.config['UPLOAD_FOLDER'] = 'upload/', upload 前面不能加“/”。

运行程序, 直接在浏览器地址栏中输入: http://127.0.0.1/upload, 效果如下所示:

image-20221126163509367image-20221126164827930

选择文件后,单击提交。上传成功会显示以下画面:

image-20221126164541444

最后,到upload文件夹中查看, 上传的文件被放到根目录的 upload 文件夹下:

image-20221126164647528

Flask WTF

Web应用程序的一个重要方面是为用户提供用户界面。HTML提供了一个标签,用于设计界面。

可以适当地使用Form(表单) 元素,例如文本输入,单选按钮,选择等。

用户输入的数据以Http请求消息的形式通过GET或POST方法提交给服务器端脚本。

  • 服务器端脚本必须从http请求数据重新创建表单元素。因此,实际上,表单元素必须定义两次 - 一次在HTML中,另一次在服务器端脚本中。
  • 使用HTML表单的另一个缺点是很难(如果不是不可能的话)动态呈现表单元素。HTML本身无法验证用户的输入。

这就是WTForms的作用,一个灵活的表单,渲染和验证库,能够方便使用。

Flask-WTF扩展为这个WTForms库提供了一个简单的接口。

使用Flask-WTF,我们可以在Python脚本中定义表单字段,并使用HTML模板进行渲染。还可以将验证应用于WTF字段。

让我们看看这种动态生成的HTML是如何工作的。

首先,需要安装Flask-WTF扩展。

pip install flask-WTF

image-20221126165233287

已安装的软件包包含一个Form类,该类必须用作用户定义表单的父级。

WTforms包中包含各种表单字段的定义。下面列出了一些标准表单字段

序号 标准表单字段与描述
1 TextField表示 HTML表单元素
2 BooleanField表示 HTML表单元素
3 DecimalField用于显示带小数的数字的文本字段
4 IntegerField用于显示整数的文本字段
5 RadioField表示 HTML表单元素
6 SelectField表示选择表单元素
7 TextAreaField表示 HTML表单元素</td> </tr> <tr> <td align="left">8</td> <td align="left"><strong>PasswordField</strong>表示<input type = 'password'> HTML表单元素</td> </tr> <tr> <td align="left">9</td> <td align="left"><strong>SubmitField</strong>表示<input type = 'submit'>表单元素</td> </tr> </tbody> </table> <p>例如,包含文本字段的表单可以设计如下:</p> <pre><code>from flask_wtf import Form from wtforms import TextField class ContactForm(Form): name = TextField("Name Of Student") </code></pre> <p>除了<strong>'name'</strong>字段,还会自动创建CSRF令牌的隐藏字段。这是为了防止<strong>Cross Site Request Forgery(**跨站请求伪造**)</strong>攻击。</p> <p>渲染时,<strong>这将导致等效的HTML脚本</strong>,如下所示:</p> <pre><code><input id = "csrf_token" name = "csrf_token" type = "hidden" /> <label for = "name">Name Of Student</label><br> <input id = "name" name = "name" type = "text" value = "" /> </code></pre> <p>在Flask应用程序中使用用户定义的表单类,并使用模板呈现表单。</p> <pre><code>from flask import Flask, render_template from forms import ContactForm app = Flask(__name__) app.secret_key = 'development key' <a href="/app.route"><a href="/app.route">@app.route</a></a>('/contact') def contact(): form = ContactForm() return render_template('contact.html', form = form) if __name__ == '__main__': app.run(debug = True) </code></pre> <p>WTForms包也包含验证器类。它对表单字段应用验证很有用。以下列表显示了常用的验证器。</p> <table> <thead> <tr> <th align="left">序号</th> <th align="left">验证器类与描述</th> </tr> </thead> <tbody> <tr> <td align="left">1</td> <td align="left"><strong>DataRequired</strong>检查输入字段是否为空</td> </tr> <tr> <td align="left">2</td> <td align="left">**Email **检查字段中的文本是否遵循电子邮件ID约定</td> </tr> <tr> <td align="left">3</td> <td align="left"><strong>IPAddress</strong> 在输入字段中验证IP地址</td> </tr> <tr> <td align="left">4</td> <td align="left"><strong>Length</strong> 验证输入字段中的字符串的长度是否在给定范围内</td> </tr> <tr> <td align="left">5</td> <td align="left"><strong>NumberRange</strong>验证给定范围内输入字段中的数字</td> </tr> <tr> <td align="left">6</td> <td align="left"><strong>URL</strong>验证在输入字段中输入的URL</td> </tr> </tbody> </table> <p>现在,我们将对联系表单中的<strong>name</strong>字段应用<strong>'DataRequired'</strong>验证规则。</p> <pre><code>name = TextField("Name Of Student",[validators.Required("Please enter your name.")]) </code></pre> <p>如果验证失败,表单对象的<strong>validate()</strong>函数将验证表单数据并抛出验证错误。<strong>Error</strong>消息将发送到模板。在HTML模板中,动态呈现error消息。</p> <pre><code>{% for message in form.name.errors %} {{ message }} {% endfor %} </code></pre> <p><strong>demo9_WTF.py文件</strong></p> <p>以下示例演示了上面给出的概念。<strong>Contact表单</strong>的设计如下<strong>(forms.py)</strong>。</p> <pre><code>from flask_wtf import FlaskForm from wtforms import TextField, IntegerField, TextAreaField, SubmitField, RadioField, SelectField from wtforms import validators, ValidationError class ContactForm(Form): name = TextField("Name Of Student",[validators.Required("Please enter your name.")]) Gender = RadioField('Gender', choices = [('M','Male'),('F','Female')]) Address = TextAreaField("Address") email = TextField("Email",[validators.Required("Please enter your email address."), validators.Email("Please enter your email address.")]) Age = IntegerField("age") language = SelectField('Languages', choices = [('cpp', 'C&plus;&plus;'), ('py', 'Python')]) submit = SubmitField("Send") </code></pre> <p>验证器应用于<strong>Name</strong> 和<strong>Email</strong>字段。</p> <p>下面给出了Flask应用程序脚本<strong>(formexample.py)</strong>。</p> <pre><code>from flask import Flask, render_template, request, flash from forms import ContactForm app = Flask(__name__) app.secret_key = 'development key' <a href="/app.route"><a href="/app.route">@app.route</a></a>('/contact', methods = ['GET', 'POST']) def contact(): form = ContactForm() if request.method == 'POST': if form.validate() == False: flash('All fields are required.') return render_template('contact.html',form = form) else: return render_template('success.html') elif request.method == 'GET': return render_template('contact.html',form = form) if __name__ == '__main__': app.run(debug = True) </code></pre> <p>模板<strong>(contact.html)</strong>的脚本如下:</p> <pre><code><html> <body> <h2 style = "text-align: center;">Contact Form</h2> {% for message in form.name.errors %} <div>{{ message }}</div> {% endfor %} <form action = "http://localhost:5000/contact" method = post> <fieldset> <legend>Contact Form</legend> {{ form.hidden_tag() }} <div style ="font-size:20px;font-weight:bold;margin-left:150px;"> {{ form.name.label }}<br> {{ form.name }} <br> {{ form.Gender.label }} {{ form.Gender }} {{ form.Address.label }}<br> {{ form.Address }} <br> {{ form.email.label }}<br> {{ form.email }} <br> {{ form.Age.label }}<br> {{ form.Age }} <br> {{ form.language.label }}<br> {{ form.language }} <br> {{ form.submit }} </div> </fieldset> </form> </body> </html> </code></pre> <p>在Python shell中运行<strong>formexample.py</strong>,访问URL <strong><a href="http://localhost:5000/contact">http://localhost:5000/contact</a></strong>。显示<strong>Contact</strong>表单将如下所示。</p> <p><img src="https://atts.w3cschool.cn/attachments/tuploads/flask/form_example.jpg" alt="Form Example"></p> <p>如果有任何错误,页面将如下所示:</p> <p><img src="https://atts.w3cschool.cn/attachments/tuploads/flask/form_error_page.jpg" alt="Form Error Page"></p> <p>如果没有错误,将显示<strong>'success.html'</strong>。</p> <p><img src="https://atts.w3cschool.cn/attachments/tuploads/flask/form_success_page.jpg" alt="Form Success Page"></p> <h1>Python 操作mysql数据库</h1> <p>Python 标准数据库接口为 Python DB-API,Python DB-API为开发人员提供了数据库应用编程接口。</p> <p>Python 数据库接口支持非常多的数据库,你可以选择适合你项目的数据库:</p> <p>GadFly、mSQL、MySQL、PostgreSQL、Microsoft SQL Server 2000、Informix、Interbase、Oracle、Sybase</p> <p>你可以访问 <a href="https://wiki.python.org/moin/DatabaseInterfaces">Python数据库接口及API</a> 查看详细的支持数据库列表。</p> <p>不同的数据库你需要下载不同的 DB API 模块,例如你需要访问 Oracle 数据库和 Mysql 数据,你需要下载 Oracle 和 MySQL 数据库模块。</p> <p>DB-API 是一个规范. 它定义了一系列必须的对象和数据库存取方式, 以便为各种各样的底层数据库系统和多种多样的数据库接口程序提供一致的访问接口 。</p> <p>Python的DB-API,为大多数的数据库实现了接口,使用它连接各数据库后,就可以用相同的方式操作各数据库。</p> <p>Python DB-API 使用流程:</p> <ul> <li>引入 API 模块。</li> <li>获取与数据库的连接。</li> <li>执行 SQL 语句和存储过程。</li> <li>关闭数据库连接。</li> </ul> <h2><strong>MySQL安装和数据库创建</strong></h2> <p>MySQL的下载网址:<a href="http://www.mysql.com/">http://www.mysql.com/</a></p> <p><strong>创建数据库:</strong></p> <p>安装完成之后,打开MySQL Workbench工具,点击“MySQL Connections”中的默认的local instance MySQL80连接,弹出数据库服务器的登录对话框。输入密码后,进入MySQL Workbench主界面。</p> <p><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126190049434.png" alt="image-20221126190049434" style="zoom:25%;" /><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126190245251.png" alt="image-20221126190245251" style="zoom:25%;" /></p> <p>在MySQL Workbench左侧菜单可以看到MySQL数据库中已有的一些数据库列表。点击工具栏中的"create a new SQL tab"图标,即可新创建一个名为Query 1的文件。</p> <p>在Query 1文件中编写创建数据库的SQL语句:</p> <pre><code class="language-mysql">#创建数据库 create database TestDB; </code></pre> <p>编写完SQL语句后,点击工具栏中的“Execute”图标,即可执行该语句,即创建数据库。并可以界面下方看到语句执行结果。</p> <p><img src="C:UsersLenovoAppDataRoamingTyporatypora-user-imagesimage-20221126190513315.png" alt="image-20221126190513315"></p> <p>接着在TestDB数据库中创建一个成员信息表 MemberInfo,MemberInfo表的字段为 MemberName, Grade, Interest。</p> <pre><code class="language-mysql">#使用数据库 use TestDB; #创建数据表 create table MemberInfo ( MemberName varchar(20), Grade int, Interest varchar(100) ); </code></pre> <p>在创建完数据表之后,可以先向表中添加一行记录,并查询看是否添加成功。</p> <pre><code class="language-mysql">#添加数据 insert into MemberInfo values('小Q', 2022, '机器人视觉'); #查询数据 select * from MemberInfo </code></pre> <p>运行结果如下:</p> <p><img src="C:UsersLenovoAppDataRoamingTyporatypora-user-imagesimage-20221126191758129.png" alt="image-20221126191758129"></p> <p><strong>Python连接MySQL数据库</strong></p> <p>要在Python中连接MySQL数据库,首先需要安装MySQLdb包。MySQLdb 是用于 Python 链接 Mysql 数据库的接口,它实现了 Python 数据库 API 规范 V2.0,基于 MySQL C API 上建立的。</p> <p>使用pip命令安装MySQL的python插件。</p> <pre><code class="language-python">pip install mysql </code></pre> <p><img src="C:UsersLenovoAppDataRoamingTyporatypora-user-imagesimage-20221126185456293.png" alt="image-20221126185456293"></p> <p><strong>数据库连接</strong></p> <p>连接数据库前,请先确认以下事项:</p> <ul> <li>您已经创建了数据库 TestDB.</li> <li>在 TESTDB 数据库中您已经创建了表 MemberInfo</li> <li>MemberInfo表字段为 MemberName, Grade, Interest。</li> <li>连接数据库 TestDB 使用的用户名为 "root" ,密码为 "123456",。</li> <li>如果您对 sql 语句不熟悉,可以访问我们的 <a href="https://www.w3cschool.cn/mysql/sql-tutorial.html">SQL基础教程</a></li> </ul> <p>创建一个demo10.py的文件,编写如下代码,连接Mysql 的TestDB 数据库:</p> <p>其中,MySQLdb.connect("localhost","root","123456","TestDB" )为数据库连接命令,<strong>localhost</strong>为MySQL数据库服务器地址,<strong>root</strong>为用户名、<strong>123456</strong>为用户密码,<strong>TestDB</strong>为要连接的数据库名称。</p> <pre><code class="language-python">import MySQLdb # 打开数据库连接 db = MySQLdb.connect("localhost","root","123456","TestDB" ) # 使用cursor()方法获取操作游标 cursor = db.cursor() # 使用execute方法执行SQL语句 cursor.execute("SELECT VERSION()") # 使用 fetchone() 方法获取一条数据。 data = cursor.fetchone() print ("Database version : %s " % data) # 关闭数据库连接 db.close() </code></pre> <p>执行以上脚本输出结果如下:</p> <p><img src="C:UsersLenovoAppDataRoamingTyporatypora-user-imagesimage-20221126192241321.png" alt="image-20221126192241321"></p> <h2>数据插入操作</h2> <p>在Python中,执行 SQL INSERT 语句向表MemberInfo中插入记录:</p> <pre><code class="language-python">import MySQLdb # 打开数据库连接 db = MySQLdb.connect("localhost", "root", "123456", "TestDB") # 使用cursor()方法获取操作游标 cursor = db.cursor() membername = "张三" grade = 2021 interest = "集群控制" # SQL 插入语句 sql = "insert into MemberInfo values('%s', %d, '%s')" % (membername, grade, interest) try: # 执行sql语句 cursor.execute(sql) # 提交到数据库执行 db.commit() except: # 发生错误时回滚 db.rollback() # 关闭数据库连接 db.close() </code></pre> <p><img src="C:UsersLenovoAppDataRoamingTyporatypora-user-imagesimage-20221126193151574.png" alt="image-20221126193151574"></p> <p>运行程序,执行正常。到MySQL Workbench中查询数据,有新插入的数据,说明数据插入成功。</p> <p><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126193215812.png" alt="image-20221126193215812" style="zoom:25%;" /></p> <h2>数据查询操作</h2> <p>Python 查询 Mysql 使用 fetchone() 方法获取单条数据, 使用 fetchall() 方法获取多条数据。</p> <ul> <li><strong>fetchone():</strong> 该方法获取下一个查询结果集。结果集是一个对象</li> <li><strong>fetchall():</strong> 接收全部的返回结果行.</li> <li><strong>rowcount:</strong> 这是一个只读属性,并返回执行 execute() 方法后影响的行数。</li> </ul> <p>查询MemberInfo 表中grade字段大于 2020 的所有数据:</p> <pre><code class="language-python">import MySQLdb # 打开数据库连接 db = MySQLdb.connect("localhost", "root", "123456", "TestDB") # 使用cursor()方法获取操作游标 cursor = db.cursor() # SQL 查询语句 g=2020 sql = "Select * From MemberInfo Where grade > %d" % (g) try: # 执行SQL语句 cursor.execute(sql) # 获取所有记录列表 results = cursor.fetchall() for row in results: mname = row[0] grade = row[1] interest = row[2] # 打印结果 print ("mname=%s, grade=%d, interest=%s" % (mname, grade, interest)) except: print ("Error: unable to fecth data") # 关闭数据库连接 db.close() </code></pre> <p>以上程序执行结果如下:</p> <p><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126194023655.png" alt="image-20221126194023655" style="zoom:25%;" /></p> <h2>数据更新操作</h2> <p>更新操作用于更新数据表的的数据,将MemberInfo 表中的 membername为“张三”的interest 字段值修改为 '去中心化联邦学习':</p> <pre><code class="language-python">import MySQLdb # 打开数据库连接 db = MySQLdb.connect("localhost", "root", "123456", "TestDB") # 使用cursor()方法获取操作游标 cursor = db.cursor() membername = "张三" interest = "去中心化联邦学习" # SQL 更新语句 sql = "update MemberInfo set interest='%s' where membername='%s'" % (interest, membername) try: # 执行sql语句 cursor.execute(sql) # 提交到数据库执行 db.commit() print ("数据更新成功!") except: # 发生错误时回滚 db.rollback() # 关闭数据库连接 db.close() </code></pre> <p>代码执行结果:</p> <p><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126194437609.png" alt="image-20221126194437609" style="zoom:25%;" /></p> <p>到MySQL Workbench中查询数据,看到数据更新成功。</p> <p><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126194457476.png" alt="image-20221126194457476" style="zoom:25%;" /></p> <h2>数据删除操作</h2> <p>删除操作用于删除数据表中的数据,删除数据表memberInfo中 grade 小于等于 2021 的所有数据:</p> <pre><code class="language-python">import MySQLdb # 打开数据库连接 db = MySQLdb.connect("localhost", "root", "123456", "TestDB") # 使用cursor()方法获取操作游标 cursor = db.cursor() g = 2021 # SQL删除语句 sql = "delete from MemberInfo where grade<=%d" % (g) try: # 执行sql语句 cursor.execute(sql) # 提交到数据库执行 db.commit() print ("数据删除成功!") except: # 发生错误时回滚 db.rollback() # 关闭数据库连接 db.close() </code></pre> <p><img src="C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20221126194949698.png" alt="image-20221126194949698" style="zoom:25%;" /></p> <h2>错误处理</h2> <p>DB API 中定义了一些数据库操作的错误及异常,下表列出了这些错误和异常:</p> <table> <thead> <tr> <th align="left">异常</th> <th align="left">描述</th> </tr> </thead> <tbody> <tr> <td align="left">Warning</td> <td align="left">当有严重警告时触发,例如插入数据是被截断等等。必须是 StandardError 的子类。</td> </tr> <tr> <td align="left">Error</td> <td align="left">警告以外所有其他错误类。必须是 StandardError 的子类。</td> </tr> <tr> <td align="left">InterfaceError</td> <td align="left">当有数据库接口模块本身的错误(而不是数据库的错误)发生时触发。 必须是 Error 的子类。</td> </tr> <tr> <td align="left">DatabaseError</td> <td align="left">和数据库有关的错误发生时触发。 必须是 Error 的子类。</td> </tr> <tr> <td align="left">DataError</td> <td align="left">当有数据处理时的错误发生时触发,例如:除零错误,数据超范围等等。 必须是 DatabaseError 的子类。</td> </tr> <tr> <td align="left">OperationalError</td> <td align="left">指非用户控制的,而是操作数据库时发生的错误。例如:连接意外断开、 数据库名未找到、事务处理失败、内存分配错误等等操作数据库是发生的错误。 必须是 DatabaseError 的子类。</td> </tr> <tr> <td align="left">IntegrityError</td> <td align="left">完整性相关的错误,例如外键检查失败等。必须是 DatabaseError 子类。</td> </tr> <tr> <td align="left">InternalError</td> <td align="left">数据库的内部错误,例如游标(cursor)失效了、事务同步失败等等。 必须是 DatabaseError 子类。</td> </tr> <tr> <td align="left">ProgrammingError</td> <td align="left">程序错误,例如数据表(table)没找到或已存在、SQL 语句语法错误、 参数数量错误等等。必须是 DatabaseError 的子类。</td> </tr> <tr> <td align="left">NotSupportedError</td> <td align="left">不支持错误,指使用了数据库不支持的函数或API等。例如在连接对象上 使用 .rollback() 函数,然而数据库并不支持事务或者事务已关闭。 必须是 DatabaseError 的子类。</td> </tr> </tbody> </table> <h1>Flask + Markdown</h1> <p><a href="https://blog.csdn.net/qq_43239441/article/details/115253422">https://blog.csdn.net/qq_43239441/article/details/115253422</a></p> <p>在前台页面中如何显示markdown的内容</p> <p>(联系我们)</p> <p><a href="https://blog.csdn.net/zyzlaozhang/article/details/127659397">https://blog.csdn.net/zyzlaozhang/article/details/127659397</a></p>