文章目录

  • 1 模板
    • 1 重定向
      • 1.1 什么是重定向?
      • 1.2 为什么要有重定向?
      • 1.3 如何使用重定向?
        • 1.3.1 暂时性重定向(代码实例):
        • 1.3.2 永久性重定向(代码实例)
    • 2 jinja2模板引擎
      • 2.1 什么是模板引擎?
      • 2.2 为什么要有模板引擎?
      • 2.3 在Flask如何使用模板引擎?
        • 2.3.1 模板引擎返回对比视图函数直接返回html代码
        • 2.3.3 模板引擎传参
          • 实例1(第一种传参方式):
          • 实例2(第二种传参方式):
          • 实例3(第三种传参方式):
          • 关键词:
          • 关键词:
        • 2.3.5 jinja2中控制语句
          • 1 jinja2中逻辑语句/if语句
            • 实例:
          • 2 jinja2中循环语句/for循环
            • 2.1 列表循环遍历项目实例:
            • 2.2 字典循环遍历项目实例:
            • for循环中的else用法
        • 2.3.6 模板加载静态文件
          • 实例:
        • 2.3.7 模板的继承
          • 具体实现:
          • 实例
    • 3 闪现
      • 3.1 在模板中获取闪现信息
        • 3.1.1 简单的在模板中实现获取闪现信息
        • 3.1.2 模板中的分类闪现
        • 3.1.3 模板中过滤闪现消息
      • 3.2 在视图中获取闪现信息
        • 3.2.1 简单的在是视图中获取闪现信息
        • 3.2.2 在视图中实现分类获取闪现信息。
  • 2 数据库
  • 1 什么是ORM?
  • 2 为什么要有ORM?
    • 3.2 数据库模型
      • 3.2.1 什么是数据库模型?
      • 3.2.2 数据库模型实例:
      • **3.2.4 **Column常用参数表:
        • server_default常用配置
      • 3.2.5 将写好的模型映射到数据库。
      • 3.2.6 更新模型
    • 3.3 数据库操作
      • 3.3.1 增
        • 实例3.3.1.1: 新增实例
        • 实例3.3.2.1: 查询实例
      • 3.3.3 改
        • 实例3.3.3.1: 修改实例

1 模板

1 重定向

1.1 什么是重定向?

重定向,顾名思义,就是重新定向到一个新的位置,比如我们在浏览器的页面自动跳转到了另一个页面,又比如访问了一个页面,然后观察网址之后并不是我们输入的网址,这个过程就是重定向完成的。

1.2 为什么要有重定向?

http状态码 应用场景 优势
暂时性重定向 302 访问一些需要权限的页面,会自动重定向到权限认证的页面 重定向在设计上会提升用户体验
永久性重定向 301 废弃原有的网址被访问,会自动重定向到新的网址确保用户访问成功 重定向在设计上会提升用户体验,有利于搜索引擎优化

例1:访问淘宝的时候,你选择了已经购买的商品,但是你并没有登录过淘宝,那么这个时候如果只是提示 “请登录再访问!”,那么相信这种设计是留不住用户的,不如直接为用户重定向到登录页面。
例2:比如想废弃原本的网址,那么用户并不知道这个事情,所以用户还是会访问原来的网址,那么就会内部做一个重定向到新启用的网址,重定向的过程会有状态码的返回,搜索引擎捕捉到重定向的代码,有利于搜索引擎优化。
关键词:重定向在设计上会提升用户体验 ,有利于搜索引擎优化

1.3 如何使用重定向?

首先从flask模块中把导入redirect

from flask import Flask,redirect

1.3.1 暂时性重定向(代码实例):

from flask import Flask,redirect
...
@app.route('/user_info/')
def user_info():name = request.args.get('name')pwd = request.args.get('pwd')if name=='mark' and pwd == '123':return '{}的信息'.format(name)return redirect('/login/')  # 可以换成 return redirect(url_for('login'))@app.route('/login/')
def login():return '这是登录页面'
...

没有通过权限验证的情况

通过权限验证的情况

**关键词:**暂时性重定向return redirect('/login/') 即可实现重定向

1.3.2 永久性重定向(代码实例)

from flask import Flask,redirect
...
@app.route('/user_info/')
def user_info():name = request.args.get('name')pwd = request.args.get('pwd')if name=='mark' and pwd == '123':return '{}的信息'.format(name)return redirect('/login/', code=301)  # 会返回301状态码给浏览器 @app.route('/login/')
def login():return '这是登录页面'
...

关键词:永久性重定向只给redirect('/login/', code=301)多加了个code=301参数

2 jinja2模板引擎

2.1 什么是模板引擎?

实现视图的业务逻辑和返回给前端的页面逻辑分离的工具,我们称之为模板引擎。
什么是模板?
模板可以理解为一个特殊的html文件,特殊之处就在于这个html文件包含固定内容和动态部分,其动态部分可以借助模板引擎进行传参

2.2 为什么要有模板引擎?

在上一章其实我们已经应用过模板引擎,试想一下如果没有模板引擎,直接给把模板的html代码写在视图函数里面,会给程序员的日常开发带来了多大的困扰,模板引擎帮我们分开了业务逻辑和页面逻辑,并且我们每次修改一个大字符串会非常不方便。模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,然后返回给浏览器,这个过程我们称之为渲染。
关键字:完成了业务逻辑和页面逻辑的分离,实现了动态的去渲染页面。

2.3 在Flask如何使用模板引擎?

Flask使用jinja2作为框架的默认模板引擎,Jinja2是基于python的模板引擎,功能比较类似于于PHPsmartyJ2eeFreemarkervelocityJinja2除了设置变量,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板的输出。并且jinja2不限制模板的格式为html,可以是任何格式的文本文件。

2.3.1 模板引擎返回对比视图函数直接返回html代码

项目目录

项目代码
**(1)login01.html **

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录界面</title>
</head>
<body>
<h1>login01</h1>  <!--login02.html文件的这一行的内容是:‘ <h1>login02</h1> ’  -->
<form action="" method="POST">用户:<input type="text" name="username">密码:<input type="text" name="password"><input type="submit" value="提交">
</form>
</body>
</html>

(2)login02.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录界面</title>
</head>
<body>
<h1>login01</h1>  <!--login02.html文件的这一行的内容是:‘ <h1>login02</h1> ’  -->
<form action="" method="POST">用户:<input type="text" name="username">密码:<input type="text" name="password"><input type="submit" value="提交">
</form>
</body>
</html>

(3) server.py

from flask import Flask, render_template
import configapp = Flask(__name__)
app.config.from_object(config)@app.route('/demo/')
def demo():return '<h2>手写html</h2>'@app.route('/demo02/')
def demo02():return '''<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录界面</title>
</head>
<body>
<!--<form action="/login_request/" method="POST">-->
<form action="" method="POST">用户:<input type="text" name="username">密码:<input type="text" name="password"><input type="submit" value="提交">
</form>
</body>
</html>'''@app.route('/demo03/')
def demo03():return render_template('login01.html')@app.route('/demo04/')
def demo04():return render_template('box/login02.html')if __name__ == '__main__':app.run()

server.py代码逻辑分析

  • * demo函数 和 demo02函数证明直接返回html代码可渲染浏览器 * demo03 证明利用模板引擎 实现了业务逻辑和页面逻辑的分离,减轻了开发的复杂度 * demo04 证明了 `render_template('box/login02.html')`的路径是templates文件夹的相对路径

#### 2.3.2 修改默认模板引擎寻找路径 Flask类中的`template_folder`参数可以指定模板寻找路径 基于上2.3.1的项目

  1. 1. 现在把templates中的文件复制到 `C:/Users/Administrator/Desktop/template_box`中,并且删除项目中的templates的文件。 2. 修改server.py中`app = Flask(__name__)`为`app = Flask(__name__,template_folder='C:/Users/Administrator/Desktop/template_box')`

**分析:** 渲染一切正常 说明Flask类中的`template_folder`参数可以指定模板寻找路径。 ![](https://img-blog.csdnimg.cn/img_convert/7bc9a74d713e88a9f613987fcd59a300.png)

2.3.3 模板引擎传参

我们之前提到过,模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,这个步骤我们就称之为模板引擎传参。
我们传参的时候要应用render_template()利用render_template的第二个参数进行传参,该函数在定义时候,第二个参数是可变长形参,所以在传值的时候我们可以传入多个关键字实参。
在模板中接收的时候使用{{}}包裹参数进行接收。

实例1(第一种传参方式):

目录结构

│ server.py
│
└─templates # 文件夹index.html

server.py

@app.route('/')
def index():return render_template('index.html',name="mark",age=18)

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>模板传参</title>
</head>
<body>{{name}}{{age}}
</body>
</html>

实例2(第二种传参方式):

目录结构:同上
server.py

@app.route('/demo1/')
def demo1():context_dict = {"name":"mark","age":"mark","sex":"girl"}return render_template('index.html',context_dict = context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>模板传参</title>
</head>
<body>{{context_dict.name}}{{context_dict.age}}{{context_dict.sex}}
</body>
</html>

实例3(第三种传参方式):

目录结构:同上
server.py

def demo2():context_dict = {"name": "mark","age": "mark","sex": "girl","other_info":{"tel":1365,"qq":565656}}return render_template('index.html',**context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>模板传参</title>
</head>
<body>{{name}}{{age}}{{sex}}{{other_info.tel}}{{other_info["qq"]}}
</body>
</html>

关键词:

在视图函数中

  • * render_template传参的时候以关键字实参进行传参。可以传多个,可以用**讲字典打散成关键字实参。

在模板中

  • * jinja2模板引擎支持接收变量在用 `{{}}`包裹参数进行接收 * 并且如果发现是字典,可以用`.`字典里面的key取出value值。也可以直接字典跟`[]`进行取值。

#### 2.3.4模板中使用url_for() 在模板中如果有使用url的需求,我们可以直接手写一个url,也可以使用`{{ url_for('视图函数名') }`动态翻转一个url。 ##### 实例: **项目目录:** ```python │ server.py │ └─templates # 文件夹 index.html info.html ``` **server.py** ```python ... @app.route('/') def index():

return render_template('index.html', name="mark", age=18)

@app.route(‘/info/’)
def info():

return render_template('info.html')

**info.html**
```python
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>信息页面</title>
</head>
<body><h1>这是信息页面</h1>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>模板传参</title>
</head>
<body><a href="/info/">正常跳转</a><a href="{{ url_for('info') }}">urlfor跳转</a>
</body>
</html>

正常跳转 和 urlfor跳转,皆可以实现跳转到info.html页面。
正常跳转就不做演示了

关键词:
  • * url_for 在视图函数中如何使用,在模板中同样的用法。 * 支持翻转查询字符串 * 支持动态路由翻转

![](https://img-blog.csdnimg.cn/img_convert/e37fd12c42278bedd03418c465bee258.png)

2.3.5 jinja2中控制语句

在jinja2中用{% %}特殊符号来编辑控制语句,一个语句以{% ... %}为起始 并且以{% end... %}来标记结束。

1 jinja2中逻辑语句/if语句

可以使用> , < , <=, ==,!=,进行判断,
也可以使用 and,or,not,()来进行逻辑合并

{% if age > 18 %}<p>成年人</p>{% elif age == 18 %}<p>刚刚成年</p>{% else %}<p>未成年</p>{% endif %}

注意:<p>只是为了渲染明显

实例:

项目目录

│ server.py
│
└─templates # 文件夹index.html

server.py

...
@app.route('/')
def hello_world():context_dict = {'age': 17,'sex': 'man',}return render_template('index.html',**context_dict)
...

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>jinja2分支</title>
</head>
<body>{% if sex == 'man' %}<p>男人</p>{% else %}<p>女人</p>{% endif %}{% if age > 18 %}<p>成年人</p>{% elif age == 18 %}<p>刚刚成年</p>{% else %}<p>未成年</p>{% endif %}
</body>
</html>

2 jinja2中循环语句/for循环

for循环可以便利任何一个可迭代对象,包括列表、字典等,支持反向遍历
列表循环:

{% for country in countrys%}<p>{{ country }}</p>{% else %}<p>没有值</p>{% endfor %}
2.1 列表循环遍历项目实例:

项目目录:

│ server.py
│
└─templates # 文件夹index.html

sever.py

@app.route('/')
def hello_world():                                             context_dict = {                                           'countrys':["1-china","2-America","3-French"]          }                                                          return render_template('index.html',**context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>for循环</title>
</head>
<body>{% for country in countrys %}  {#    {% for country in countrys|reverse %} 可以实现反向遍历#}<p>{{ country }}</p>{% else %}<p>没有值</p>{% endfor %}</body>
</html>

反向遍历实例
server.py{% for country in countrys %} 改为 {% for country in countrys|reverse %}
可以实现反向遍历,运行效果如下图

2.2 字典循环遍历项目实例:

项目目录

│ server.py
│
└─templates # 文件夹index.html

sever.py

@app.route('/')
def hello_world():                                      context_dict = {                                    'countrys':["1-china","2-America","3-French"]   }                                                   return render_template('index.html',**context_dict) @app.route('/demo/')
def demo():                                             context_dict ={                                     'colleges':[                                    {                                           'name': '清华大学',                         'area': '北京'                            },                                          {                                           'name': '复旦大学',                         'area': '上海'                            ''                                      },                                          {                                           'name': '吉林大学',                         'area': '吉林'                            },                                          {                                           'name': '中山大学',                         'area': '广东'                            }                                           ]                                               }                                                   return render_template('index.html',**context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>for循环</title>
</head>
<body><table><tr><th>1开始的序号</th><th>0开始的序号</th><th>大学名称</th><th>所属地区</th><th>总数</th></tr>{% for college in colleges %}{% if loop.first %}<tr style="background: blue">{% elif loop.last %}<tr style="background: yellow ">{% else %}<tr>{% endif %}<td>{{ loop.index }}</td><td>{{ loop.index0 }}</td><td>{{ college.name }}</td><td>{{ college.area }}</td><td>{{ loop.length }}</td></tr>{% endfor %}</table></body>
</html>

for循环常用变量表

for循环常用变量 功能描述
loop.index 当前循环的索引(从1开始)
loop.index0 当前循环的索引(从0开始)
loop.first 是否是第一次循环,是返回True,否则返回Flase
loop.last 是否是最后一次循环,是返回True,否则返回Flase
loop.length 总共可以循环的次数 / 迭代器的长度
for循环中的else用法

for还可以else分支语法,如果for内部没有遍历出来内容,那么就会走else分支,反之如果for循环遍历出了内容,则不会运行else分支。
注意:jinja2中的forelse逻辑不通于python在此不要类比python中的 forelse

{% for country in countrys|reverse %}<p>{{ country }}</p>{% else %}<p>没有值</p>{% endfor %}

2.3.6 模板加载静态文件

在模板中加载静态文件的时候也要使用到url_for()函数,去寻找具体的静态文件资源。第一个参数是定位到static文件夹,filename参数定位到static文件夹内的具体资源。

{{ url_for('static',filename='相对于static文件夹的路径') }}
实例:

项目目录:

│  app.py
│
├─static  # 文件夹
│  ├─css  # 文件夹
│  │      demo.css
│  │
│  ├─images  # 文件夹
│  │      1.png
│  │
│  └─js  # 文件夹
│          demo.js
│
├─templates  # 文件夹index.html

app.py

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

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>静态文件加载</title><link rel="stylesheet" href="{{ url_for('static',filename='css/demo.css') }}"><script src="{{ url_for('static',filename='js/demo.js') }}"></script></head>
<body><img src="{{ url_for('static',filename='images/1.png') }}">
</body>
</html>

demo.css

body{background: red;
}

demo.js

alert('hello world')

2.3.7 模板的继承

jinja2的模板继承可以把一些公共的代码定义到一个基模板中,比如把导航栏、页脚等通用内容放在基模板中,以后所有的子模板直接继承基模板,在子模板被渲染时会自动包含继承基模板的内容,通过模板的继承可以避免在多个模板中编写重复的代码。

具体实现:

在基模板中定义一些公共的代码,子模板会继承这些公共的代码,但是子模板需要根据自己的需求去实现不同的代码,这个时候就需要在基模板中提供一些接口,以便子模板实现自己的业务需求。
1 基本写法
在基/父模板中定义接口(block)

{% block main %} {# main是自定义的变量名 #}{% endblock %}

在子模板中继承父模板,并且重写接口(block)

{% extends 'base.html' %} {# extends 后面跟的参数是导入的基模板相对于templates的路径 #}
{% block main %}{% endblock %}

2 子模板中调用父模板代码block中的代码
基模板中

{% block main %}
<p>父模板中main中原有的内容</p>{% endblock %}

子模板中:

{% block main %}{{ super() }}   {# 保留基模板中本块的代码 #}<p>子模板中重写main的内容 </p>
{% endblock %}

3 在子模板中调用其他block中的代码:
子模板中:

{% block main %}{{ self.demo() }} {# self.其他block名字 #}<p>子模板中重写main的内容 </p>
{% endblock %}

4 子模板中的想定义自己的代码只能放到block中,否则无效

实例

注意:这里面我们使用了bootstrap框架。
bootstrap3的中文官网:https://v3.bootcss.com/
1 首先下载 用于生产环境的 Bootstrap

2 解压出来里面的css文件
项目目录

│  app.py
│
├─static  # 文件夹
│  └─css
│          bootstrap-theme.css
│          bootstrap-theme.css.map
│          bootstrap-theme.min.css
│          bootstrap-theme.min.css.map
│          bootstrap.css
│          bootstrap.css.map
│          bootstrap.min.css
│          bootstrap.min.css.map
│
├─templates  # 文件夹base.htmldetail.html

css文件夹: 是从我们上面下载好的用于生产环境的 Bootstrap中解压出来的
base.html 注意:里面的form标签中的内容和nav标签中的内容均是bootstrap框架的代码截取,div标签是用于清除浮动

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>父模板</title><link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.css') }}">
</head>
<body><form class="navbar-form navbar-left" role="search"><div class="form-group"><input type="text" class="form-control" placeholder="Search"></div><button type="submit" class="btn btn-default">Submit</button></form><div style=" visibility:hidden;display:block;font-size:0;clear:both;height:50px"></div>{% block main %}<p>父模板中main中原有的内容</p>{% endblock %}<br><br><br>{% block demo %}<p>demo中原有的内容</p>{% endblock %}<div style=" visibility:hidden;display:block;font-size:0;clear:both;height:0"></div>
<nav aria-label="Page navigation"><ul class="pagination"><li><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li><li><a href="#">1</a></li><li><a href="#">2</a></li><li><a href="#">3</a></li><li><a href="#">4</a></li><li><a href="#">5</a></li><li><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li></ul>
</nav></body>
</html>

detail.html

{% extends 'base.html' %}
{% block demo %}<p>子模板中重写demo的内容</p>
{% endblock %}
{% block main %}{{ super() }}   {# 保留基模板中本block的代码 #}{{ self.demo() }} {# 调用demo block的代码 #}<p>子模板中重写main的内容 </p>
{% endblock %}

app.py 注意:app.config.update(TEMPLATES_AUTO_RELOAD=True)语句用于每次都重新加载模板文件

from flask import Flask, render_templateapp = Flask(__name__)
app.config.update(TEMPLATES_AUTO_RELOAD=True)@app.route('/')
def hello_world():return render_template('base.html')@app.route('/demo/')
def demo():return render_template('detail.html')if __name__ == '__main__':app.run()

子模板运行效果

3 闪现

插图:恶搞图05

3.1 在模板中获取闪现信息

Flask 提供了一个非常简单的方法来使用闪现系统向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息,然后在且仅仅在下一个请求中访问这个数据,强调flask闪现是基于flask内置的session的,利用浏览器的session缓存闪现信息。所以必须设置secret_key

3.1.1 简单的在模板中实现获取闪现信息

实例:
server.py

from flask import Flask, flash, redirect, render_template, \request, url_forapp = Flask(__name__)
app.secret_key = 'some_secret'@app.route('/')
def index():return render_template('index.html')@app.route('/login', methods=['GET', 'POST'])
def login():error = Noneif request.method == 'POST':if request.form['username'] != 'admin' or \request.form['password'] != '123':error = '登录失败'else:flash('恭喜您登录成功')return redirect(url_for('index'))return render_template('login.html', error=error)if __name__ == "__main__":app.run()

注意:这个 flash() 就可以实现在下一次请求时候,将括号内的信息做一个缓存。不要忘记设置secret_key
这里是 index.html 模板:

{% with messages = get_flashed_messages() %}  # 获取所有的闪现信息返回一个列表{% if messages %}<ul class=flashes>{% for message in messages %}<li>{{ message }}</li>{% endfor %}</ul>{% endif %}
{% endwith %}<h1>主页</h1><p>跳转到登录页面<a href="{{ url_for('login') }}">登录?</a>

注意:{% with messages = get_flashed_messages() %} # 获取所有的闪现信息返回一个列表
这里是login.html 模板

<h1>登录页面</h1>
{% if error %}
<p class=error><strong>Error:</strong> {{ error }}
{% endif %}<form action="" method=post>用户名:<input type=text name=username>密码:<input type=password name=password><p><input type=submit value=Login></p>
</form>

简单的在模板中实现获取闪现信息小结:

设置闪现内容:flash('恭喜您登录成功')
模板取出闪现内容:{% with messages = get_flashed_messages() %}

3.1.2 模板中的分类闪现

当闪现一个消息时,是可以提供一个分类的。未指定分类时默认的分类为 'message' 。 可以使用分类来提供给用户更好的反馈,可以给用户更精准的提示信息体验。
要使用一个自定义的分类,只要使用 flash() 函数的第二个参数:

flash('恭喜您登录成功',"status")
flash('您的账户名为admin',"username")

在使用get_flashed_messages()时候需要传入with_categories=true便可以渲染出来类别

{% with messages = get_flashed_messages(with_categories=true) %}{% if messages %}<ul class=flashes>{% for category, message in messages %}<li class="{{ category }}">{{ category }}:{{ message }}</li>{% endfor %}</ul>{% endif %}
{% endwith %}

模板中的分类闪现小结:

分类设置闪现内容:flash('恭喜您登录成功',"status")flash('您的账户名为admin',"username")
模板取值:   {% with messages = get_flashed_messages(with_categories=true) %}{% if messages %}<ul class=flashes>{% for category, message in messages %}...

3.1.3 模板中过滤闪现消息

同样要使用一个自定义的分类,只要使用 flash() 函数的第二个参数:

flash('恭喜您登录成功',"status")
flash('您的账户名为admin',"username")

在使用get_flashed_messages()时候需要传入category_filter=["username"]便可根据类别取出闪现信息。中括号内可以传入的值就是类别,可以传入多个。

{% with messages = get_flashed_messages(category_filter=["username"]) %}
{% if messages %}<ul>{%- for message in messages %}<li>{{ message }}</li>{% endfor -%}</ul>
</div>
{% endif %}
{% endwith %}

小结:

分类设置闪现内容:flash('恭喜您登录成功',"status")flash('您的账户名为admin',"username")
模板取值:  % with messages = get_flashed_messages(category_filter=["username"]) %}{% if messages %}<ul>{%- for message in messages %}

3.2 在视图中获取闪现信息

3.2.1 简单的在是视图中获取闪现信息

-设置: flash('xxx')
-取值:get_flashed_message() # 注意这个不同于模板取值,这个是从flask中导入的
-注意:在视图中获取闪现信息不必非得是两次连续的请求,只要保证是第一次取相应的闪现信息,就可以取得到。

实例:

from flask import Flask, request, flash, get_flashed_messages
import osapp = Flask(__name__)
app.secret_key = os.urandom(4)
app.debug = True@app.route('/login/')
def login():if request.args.get('name') == 'rocky':return 'ok'flash('第一条闪现信息:用户名不是rocky填写的是{}'.format(request.args.get('name')))# flash('第二条闪现信息:用户名不是rocky填写的是{}'.format(request.args.get('name')))return 'error,设置了闪现'
@app.route('/get_flash/')
def get_flash():#get_flashed_messages()是一个列表列表可以取出闪现信息,该条闪现信息只要被取出就会删除掉。return '闪现的信息是{}'.format(get_flashed_messages())@app.route('/demo/')
def demo():return 'demo'if __name__ == '__main__':app.run()

(1)**会触发设置闪现内容

**(2)**取出闪现内容

**(3)**再次取出闪现内容,发现闪现内容取出一次后就为空了

小结:

  • * get_flashed_messages()是一个列表,该列表可以取出闪现信息,该条闪现信息只要被取出就会删除掉。

![](https://img-blog.csdnimg.cn/img_convert/241450bf9f02fde34fcb14e0fdad5cbe.png)

3.2.2 在视图中实现分类获取闪现信息。

-设置:flash('用户名错误', "username_error")flash('用户密码错误', "password_error") # 第二个参数为闪现信息的分类。-取所有闪现信息的类别和闪现内容:get_flashed_messages(with_categories=True)-针对分类过滤取值:get_flashed_messages(category_filter=['username_error']) # 中括号内可以写多个分类。-注意:如果flash()没有传入第二个参数进行分类,默认分类是 'message'

实例1

@app.route('/login/')
def login():if request.args.get('name') == 'rocky':return 'ok'flash('用户名错误', category="username_error")flash('用户密码错误', "password_error")return 'error,设置了闪现'
@app.route('/get_flash/')
def get_flash():return '闪现的信息是{}'.format(get_flashed_messages(with_categories=True))

把所有的闪现类别和闪现信息返回。

实例2

@app.route('/login/')
def login():if request.args.get('name') == 'rocky':return 'ok'flash('用户名错误', category="username_error")flash('用户密码错误', "password_error")return 'error,设置了闪现'
@app.route('/get_flash/')
def get_flash():return '闪现的信息是{}'.format(get_flashed_messages(category_filter=['username_error']))

返回页面只显示了 "username_error"的分类内容。

2 数据库

数据库,顾名思义是储存数据的仓库,常见的管理数据库的软件被称为数据库管理系统(DBMS, Database Management System), 常见的DBMS有 MySQL、PostgreSQL、SQLite、MongoDB。这些常见的DBMS我们可以把他们理解为专门负责搬运数据的管理的数据的程序。

1 什么是ORM?


对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 。 ORM是“对象-关系-映射”的简称。在我们的web应用开发中ORM把底层的SQL数据实体转化成高层的Python对象。只需要通过Python代码即可完成数据库操作。

2 为什么要有ORM?

在web应用里使用原生的SQL语句操作数据库固然能达到我们处理储存数据的需求,但是会存在以下三类问题:

  • * 手动编写SQL语句比较复杂耗时(当然因人而异,如果热衷于原生sql,并不影响开发),并且视图函数中写大量SQL语句会降低代码的易读性。 * 比较容易出现安全问题,如SQL注入。 * 对于不同的DBMS,需要使用不同的Python接口库,语法各不相同,很难有标准化的代码流程。

使用ORM可以很大程度上解决这些问题,在python中,ORM把底层的SQL数据实体转化成高层的Python对象。这样的好处是,你甚至不需要了解SQL,只需要操作Python对象的即可完成数据库操作。 **使用ORM的优势:**

  • * 提升开发效率。从高层对象转换成原生SQL会牺牲一些性能,但这微不足道的性能牺牲换取的是巨大开发效率提升。 * 可移植性好。它实现了数据库模型与DEMS的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库。通常一个orm支持很多的DEMS,如1MySQL、PostgreSQL、Oracle、SQLite等,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。

# 3 如何在Flask应用ORM? 选择ORM框架时,在我们Flask中更推荐使用Flask的扩展组件Flask-SQLchemy 。Python实现的ORM有SQLAlchemy、Peewee、PonyORM等,其中SQLAlchemy是Python社区使用最广泛的ORM之一,Flask-SQLchemy正是基于SQLchemy。 ![](https://img-blog.csdnimg.cn/img_convert/dc5550be1565c5224b28e443277e573b.gif) ## 3.1 连接数据库: 首先切入到我们的虚拟环境 ,安装我们的 `Flask-SQLchemy` ```python pip install flask-sqlalchemy pip install pymysql ``` 这里我们的`DBMS`以`mysql`数据库为例, 连接数据库 **实例** ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy

app = Flask(name)
HOST = ‘127.0.0.1’
PORT = ‘3306’
DATABASE_NAME = ‘01_db’
USERNAME = ‘root’
PASSWORD = ‘root’

DB_URI = “mysql+pymysql://{username}:{password}@{host}:{port}/{databasename}?charset=utf8mb4”
.format(username=USERNAME,password=PASSWORD,host=HOST,port=PORT,databasename=DATABASE_NAME)

app.config[‘SQLALCHEMY_DATABASE_URI’] = DB_URI
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’]= False

db = SQLAlchemy(app)

**解读:**
**1**  从`flask_sqlalchemy`模块中导入`SQLAlchemy`类
```python
from flask_sqlalchemy import SQLAlchemy

2 app对象通过变量SQLALCHEMY_DATABASE_URI加载配置好的URI(统一资源标识符),URI内包含了各种用于连接数据库的信息,指向一个具体的库。
常用数据库的URI格式

HOST = '127.0.0.1'  # ip
PORT = '3306'        # 端口
USERNAME = 'root'    # 数据库账号
PASSWORD = 'root'   # 密码
DATABASE_NAME = '01_db'  # 具体的一个库名
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{databasename}?charset=utf8mb4"\
.format(username=USERNAME,password=PASSWORD,host=HOST,port=PORT,databasename=DATABASE_NAME)app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI

3 SQLALCHEMY_TRACK_MODIFICATIONS这个配置变量决定是否追踪对象的修改,这用于FLask- SQLALchemy的事件通知系统。这个配置键默认值为None,如果没有特殊需要我们把它设置为Flase, 避免造成一些没必要的性能浪费。

app.config['SQLALCHEMY_TRACK_MODIFICATIONS']= False

4 SQLAlchemy类传入app类,引用app配置定位到具体的数据库,并且实例化出db对象,这个db对象代表我们的数据库,并且通过这个对象操作我们的ORM

db = SQLAlchemy(app)

3.2 数据库模型

3.2.1 什么是数据库模型?

继承了db.Model的python类,并且这个python类映射到数据库为一个表,这个python类称之为数据库模型。每个数据库模型都对应着数据库中的一个表。

3.2.2 数据库模型实例:

class UserInfo(db.Model):__tablename__ = 'user_info'id = db.Column(db.Integer,primary_key=True,autoincrement=True)username = db.Column(db.String(20),nullable=False)
  • * `__tablename__`可以直接指定表名(推荐使用)。如果没有写`__tablename__`指定表名,此类名可以自动转化为表名(不推荐使用)。

类名自动转化表名的方式为User–> user# 单个单词转换为小写
UserInfo–> user_info# 多个单词转换为小写并使用下划线分隔
如UserInfo类在没有 __tablename__指定表名时候,UserInfo类会自动映射到数据库的表名为user_info

  • db.Column类实例化表示字段(表示数据库中的列),该类实例化出的对象被一个变量接受,该变量表示字段名。该类实例化时传入的参数表示字段的约束。

如:id = db.Column(db.Integer,primary_key=True,autoincrement=True)表示该表内id字段为主键并且自动增长。

![](https://img-blog.csdnimg.cn/img_convert/5552b6115fa22e1070b0274a1ecbb3b4.png) ### 3.2.3 常用的字段类型表: | 字段 | 说明 | 映射到数据库对应类型 | | :--: | :--: | :--: | | Integer | 整数 | int类型 | | String | 字符串,String类内可选择length参数的值用于设置最大字符个数 | varchar类型 | | Text | 用于储存较长的Unicode文本,,理论上可以储存65535个字节 | text类型 | | Date | 日期,存储Python的datetime.date 对象 | date类型 | | Time | 时间,存储Python的datetime.time 对象 | time类型 | | DateTime | 时间和日期,存储Python 的datetime 对象 | datetime类型 | | Float | 浮点类型 | float类型 | | Double | 双精度浮点类型,比浮点类型小数位精度更高。 | double类型,占据64位。 | | Boolean | 布尔值 | tinyint类型 | | Enum | 枚举类型 | enum类型 |

**3.2.4 **Column常用参数表:

约束 说明
primary_key 如果设为True,该列就是表的主键
unique 如果设为True,该列每个值唯一,也就是该字段不允许出现重复值
index 如果设为True,为这列创建索引,用于提升查询效率
nullable 如果设为True,这列允许使用空值,反之则不允许使用空值。
server_default 为这列定义默认值, 默认值只支持字符串,其他类型需要db.text()方法指定
default 为这列定义默认值,但是该约束并不会真正映射到表结构中,该约束只会在ORM层面实现(不推荐使用)
comment 该字段的注释
name 可以使用该参数直接指定字段名
autoincrement 设置这个字段为自动增长的。
server_default常用配置
配置默认值类型 代码
更新datatime时间 server_default = db.text(“CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”)
当前的datatime时间 server_default = db.text(“CURRENT_TIMESTAMP”)
数字 server_default=“数字”
布尔 server_default=db.text(‘True’) / server_default=db.text(‘False’)/ server_default=‘数字’

3.2.5 将写好的模型映射到数据库。

class UserInfo(db.Model):__tablename__ = 'user_info'id = db.Column(db.Integer,primary_key=True,autoincrement=True)username = db.Column(db.String(20),nullable=False)db.create_all()

如果你已经定义好了一个继承db.Model的类,我们把这个类称之为模型。我们想把这个模型映射到数据库中,也就是在数据库中创建这个模型所描述的一张表,使用db.create_all()可以实现把继承了该db.model的所有模型创建到数据库中。查看数据库的时候我们会发现多了一张user_info表。

3.2.6 更新模型

如果我们要更新一个模型,并且想把这个新的模型映射到数据库中,直接使用db.create_all()会无效,因为原来已经存在了这张表,为了解决这个问题我们可以先db.drop_all()删除该库下的所有继承了db.model的模型表,然后再db.create_all()使得继承了db.model的所有模型表映射到数据库中,从而创建我们更新的表。这种方式的原理是先删除数据库中原来所有的模型表,然后在新建所有需要映射的模型表,这种方式的弊端是它把数据库中原有的数据都销毁了。
为了解决这种更新模型导致删除掉原来的数据的弊端。下一章将会介绍一种更好的方式用于更新数据库。

3.3 数据库操作

3.3.1 增

模型表 映射到数据中

class School(db.Model):__tablename__ = "school"id = db.Column(db.Integer,primary_key=True,nullable=False,autoincrement=True,comment="ID")name = db.Column(db.String(30),nullable=False,server_default='',comment="学校名称")area = db.Column(db.String(30),nullable=False,server_default='',comment="所属地区")score = db.Column(db.Integer,nullable=False,server_default='600',comment="录取分数线")def __repr__(self):return "<School(name:{})>".format(self.name)db.create_all()

实例3.3.1.1: 新增实例

新增四条记录映射到数据库中

school_01 =School(name="北京大学",area="北京",score=658)  # 实例化模型类作为一条记录
school_02 =School(name="清华大学",area="北京",score=667)
school_03 =School(name="中山大学",area="广东",score=645)
school_04 =School(name="复旦大学",area="上海",score=650)db.session.add(school_01)   # 把新创建的记录添加到数据库会话
db.session.add(school_02)
db.session.add(school_03)
db.session.add(school_04)db.session.commit()  # 提交数据库会话

提示:数据库会话db.session和后面介绍的Flasksession对象没有关系。db.session是数据库会话也称为事务。

  1. 1. 实例化模型类创建对象,该对象作为一条记录,实例化的过程传入的参数为字段内容。 2. 把新创建的记录添加到数据库会话。 3. 提交数据库会话

**查看数据库** ![](https://img-blog.csdnimg.cn/img_convert/bf227d2270d73193c87a029c26f49b66.png) *提示1 :如果add多条记录可以使用add_all()一次添加包含多条记录的列表* *如:`db.session.add_all([school_01,school_02,school_03,school_04])`* ### 3.3.2 查

在我们的flask中db.session出的对象调用query属性,可以通过query属性调用各种过滤方法完成查询。

模型类.<过滤方法>.<查询方法>

常用过滤器表:

过滤器 说明
filter() 使用指定的规则过滤记录相当于sql的where约束条件,返回一个新查询
filter_by() 同filter原理,不同的是查询的时要使用关键字参数,返回一个新查询
limit() 使用指定的值限制原查询返回的结果的数量,返回一个新查询
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结构进行排序,返回一个新查询
group_by() 根据指定条件对原来查询结构进行分组,返回一个新查询

实例3.3.2.1: 查询实例

下面几个查询案例需要在实例3.3.1完成的基础上操作
all()返回一个列表,列表里存放所有符合条件的记录

all_school = School.query.all()
print(all_school) # 输出:[<School(name:北京大学)>, <School(name:清华大学)>, <School(name:中山大学)>, <School(name:复旦大学)>]

first()返回符合条件的第一条记录:

school_01 =School.query.first()
print(school_01)# 输出:<School(name:北京大学)>

get()返回指定主键值(id字段)的记录:

school_01 = School.query.get(1)
print(school_01)#输出:<School(name:北京大学)>

filter() 使用指定的规则过滤记录相当于sql的where约束条件,返回新产生的查询对象。

beijing_all = School.query.filter(School.area == "北京").all()
beijing_first = School.query.filter(School.area == "北京").first()
print(beijing_all)
print(beijing_first)# 输出:[<School(name:北京大学)>, <School(name:清华大学)>]
#       <School(name:北京大学)>

filter_by:同filter()效果一样,查询的时候使用关键字参数查询(无法进行多表复杂查询,不推荐使用)

zhongshan_school = School.query.filter_by(name='中山大学').all()
print(zhongshan_school)# 输出:[<School(name:中山大学)>]

db.session.qury(模型类)等价于模型类.query,db.session.qury功能更强大一些,可以进行多表查询。

fudan_school = School.query.filter(School.name == '复旦大学').first()
print(fudan_school)
# 输出:<School(name:复旦大学)>fudan_school = db.session.query(School).filter(School.name == '复旦大学').first()
print(fudan_school)
# 输出:<School(name:复旦大学)>

提示:其他的过滤器会在接下来的章节具体根据实际案例讲解

3.3.3 改

实例3.3.3.1: 修改实例

修改北京大学的录取成绩

beida = School.query.filter(School.name=='北京大学').first()
beida.score = 630
db.session.commit()


更新一条记录分为一下几部:

  1. 1. 找到对应的记录对象 2. 修改记录对象的属性 3. 直接调用`db.session.commit()`提交会话 *提示:只有要插入新的记录或要将现有的记录添加到会话中时才需要使用add()方法。只是更新现有记录的时可以修改记录对象属性后直接提交会话*

### 3.3.4 删 ![](https://img-blog.csdnimg.cn/img_convert/a6463fba479b0bc03aa17d24a7831191.gif) #### 实例3.3.4.1: 删除实例 **从数据库中删除清华大学相关信息** ```python qinghua = School.query.filter(School.name=='清华大学').first() db.session.delete(qinghua) db.session.commit() ``` ![](https://img-blog.csdnimg.cn/img_convert/e6e91a78632d962c477b38f0eba935e2.png) 删除一条记录分为以下几步:

  1. 1. 找到对应的记录对象 2. 需要调用`delete()`方法在会话中标识需要删除的记录,具体是把该记录对象传入`db.session.delete(记录对象)`实现标识。 3. 调用`db.session.commit()`提交会话。

Flask框架——模板、数据库ORM相关推荐

  1. flask html 模板继承,Flask框架模板继承实现方法分析

    Flask框架模板继承实现方法分析 本文实例讲述了Flask框架模板继承实现方法.分享给大家供大家参考,具体如下: 在模板中,可能会遇到以下情况: 多个模板具有完全相同的顶部和底部内容 多个模板中具有 ...

  2. mysql django构架图_Django框架之数据库ORM框架

    首先,我来介绍一下什么是ORM框架: O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思.在ORM框架中,它帮 ...

  3. Flask 框架 - 模板 - 2

    1 学习目标 能够说出Flask中模板代码复用的三种方式 能够使用代码实现模板继承的功能 能够说出可以在模板中直接使用的 Flask 变量和函数 能够使用 Flask-WTF 扩展实现注册表单 能够说 ...

  4. flask框架+mysql数据库并与前台数据交互

    在Flask使用数据库 我们将使用Flask-SQLAlchemy 的扩展来管理数据库.由SQLAlchemy项目提供的,已封装了关系对象映射(ORM)的一个插件. ORMs允许数据库程序用对象的方式 ...

  5. python的flask框架mysql数据库迁移

    最近在学习<flaskweb开发>,教程里采用 sqlite 数据库,我自己用的是mysql,在到数据库迁移部分有点懵了,想跳过去,但是到后面发现很不方便,于是折腾了好长时间,网上也找不到 ...

  6. flask框架创建数据库定义字段类型和字段常用参数

    1.字段类型 Integer int整型,普通整数,一般是32位 SmallInteger int 取值范围最小的整型,一般是16位 Big Integer int或long 不限制精度的整数 Flo ...

  7. flask mysql项目模板渲染_Flask框架模板渲染操作简单示例

    本文实例讲述了Flask框架模板渲染操作.分享给大家供大家参考,具体如下: from flask import render_template from flask import Flask from ...

  8. flask框架中的Jinja2模板引擎

    简介 在flask框架中通常使用Jinja2模板引擎来实现复杂页面的渲染. 本章主要介绍Jinja2模板引擎的基本结构和使用方法. 如何使用flask框架渲染模板 在模板中传递一个或者多个参数 if语 ...

  9. python flask框架实例_Flask框架的一个小案例

    这个案例简单的实现了Flask框架的原理,运用python中的Flask框架从数据库中提取数据,前端页面运用echarts渲染 后端代码: from flask import Flask,render ...

最新文章

  1. map python2 python3 兼容_windows下 兼容Python2和Python3的解决方法
  2. 同感,C#对JSON序列化和反序列化有点蹩脚
  3. 环形队列PHP,环形队列 - Go语言中文网 - Golang中文社区
  4. Linux HOOK
  5. 计算机视觉招聘_香港理工大学人工智能设计实验室科研招聘
  6. HDFS的API调用,创建Maven工程,创建一个非Maven工程,HDFS客户端操作数据代码示例,文件方式操作和流式操作
  7. 让系统通过域用户自动打补丁
  8. linux bin文件制作
  9. nginx $mail-send()发送邮件报错_基于SMTP协议的E-MAIL电子邮件发送客户端软件C#实现...
  10. 9.27模拟:至暗时刻
  11. java 停止线程播放音频_Notification 播放 关闭 声音----转载
  12. Chrome浏览器显示“网站连接不安全”怎么解决?解决方法分享
  13. c# 日期函数[string.Format----GetDateTimeFormats] --转载
  14. python数组取数_python 取数组
  15. Flash 3D 基础
  16. StringUtil
  17. centos7 禁止ip访问_centos7下使用iptables屏蔽所有中国IP
  18. python cpk计算器_CPK公式
  19. 【系统分析师】考试内容大纲内容
  20. Python之quote() unquote()使用

热门文章

  1. DVWA 不跳转_触发器+VBA……PPT:我不做幻灯片了jojo!
  2. 2022年几款好用的固定资产管理系统推荐
  3. 观察者模式,策略模式,适配器模式
  4. 手把手教你原生JavaScript打造丝滑流畅的轮播图,让你的网站瞬间提升用户体验
  5. 微信小程序 |做一款跟ChatGPT下五指棋的小程序
  6. 超搞笑生日祝福语送给朋友【荐】
  7. 计算机屏幕的面积约是6什么,在你心里中南大学到底有多大呢?
  8. DBEX-1-2-os_db_2000
  9. 用matlab计算稳态误差,利用Matlab求稳态误差的两种方法.
  10. iPhone文件读写