官方文档:http://flask.pocoo.org/docs/

中文文档:http://docs.jinkan.org/docs/flask/

视频地址:https://www.bilibili.com/video/av67507215/

Flask一样是MVC的设计模式:
核心思想:解耦

  1. Model:用于封装与应用程序的业务逻辑相关的数据及对数据的处理方法,是Web应用程序中用于处理应用程序的数据逻辑部分,Model通常只提供功能性的接口,通过这些接口可以获取Model的所有功能。
  2. View:负责数据的显示和呈现,view是对用户的直接输出。
  3. Controller:负责从用户端收集用户的输入,可以看成提供view的反向功能,主要处理用户交互。

1560390654323

使用Flask

Flask的使用十分简易,不需要像Django一样创建project,分出apps,template,view,model等等,只需要创建一个py文件:

1
2
3
4
5
6
7
8
9
10
# firstFlask
from flask import Flask

app = Flask(__name__)

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

app.run()

运行得到:

1
2
3
4
5
6
7
8
 * Serving Flask app "firstflask" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [13/Jun/2019 10:00:21] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [13/Jun/2019 10:00:22] "GET /favicon.ico HTTP/1.1" 404 -

1560391462472

当然了,肯定不会真的就把一个项目写在一个py文件中,还是需要分开的.


Django里有Settings.py,那么Flask如何添加参数,一般是在run()里添加:

  • debug是否开启调试模式,开启后修改过python代码会自动重启
  • threaded是否开启多线程
  • port启动指定服务器的端口号
  • host主机,默认是127.0.0.1,指定为0.0.0.0代表本机所有ip
1
2
if __name__ == '__main__':
app.run(debug=True,port=5000,host='0.0.0.0')

flask-script插件:

1
pip install flask-script

可以实现命令行参数接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# manage.py
from flask import Flask
from flask_script import Manager

app = Flask(__name__)

manager = Manager(app=app)

@app.route('/')
def index():
return 'Hello Flask3'

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

manage.py不能被其它文件导入!

之后执行python manage.py runserver即可,像极了Django

manage的参数使用:

  • -d : 是否开启调试模式
  • -r : 是否自动重新加载文件
  • -h--host : 指定主机
  • -p,--port : 指定端口
  • --threaded : 是否使用多线程
  • -? --help : 查看帮助

所以可以如下使用:

1
python manage.py runserver -d -r -h  0.0.0.0 -p 9000

manage可以进入flask的shell环境


flask的简单应用:
文件层级:

1
2
3
4
5
6
7
webproject
|-- static
|-- css
|-- hello.css
|-- templates
|-- hello.html
|-- manage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# manage.py
from flask import Flask,render_template
from flask_script import Manager

app = Flask(__name__)

manager = Manager(app=app)

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

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

if __name__ == '__main__':
manager.run()
1
2
3
4
5
6
7
8
/* static/css/hello.css */
h2 {
color: green;
}

p {
color: yellow;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- templates/hello.html -->
<!DOCTYPE html>
<html lang='cn'>
<head>
<meta charset="UTF-8">
<title>hello world</title>
<link rel="stylesheet" href="/static/css/hello.css">
</head>

<body>
<h2>hello world</h2>
<p>123</p>
</body>
</html>

1560397591557

静态文件也是可以直接访问:

1560397621990


Flask的流程和Django基本一致

1560398200099

Django的url分发器是放在urls.py里面,Flask则是放在app.route装饰器里面:
Flask获取参数方式就是Django2.0版本的方式,使用尖括号:

1
2
3
4
# 注意装饰器的url参数要和函数的参数对应(就是这里的hehe)
@app.route('/hello/<hehe>/')
def params(hehe):
return hehe

1560398721604

1560398744126

Flask的请求参数:

  • 都是关键字参数

  • 默认标识是尖括号(如/hello/<name>/)

  • name需要和对应的视图函数的参数名宇保持一致

  • 参数允许有默认值:

    • 如果有默认值,那么在路由中,不传输参数也是ok的
    • 如果没有默认值,参数在路由中必须传递
  • 和Django一样,url参数的默认类型是string,但是Flask可以手动修改:
    在装饰器里修改如下:

    1
    2
    3
    4
    @app.route('/get/<int:num>/')
    def get(num):
    print(type(num)) # int
    return '789'

    除了int还有:

    • float

    • string(默认):
      将斜线认为是参数分隔符

    • path :
      接受到数据格式是字符串,
      特性 : 会将斜线认为是一个字符

      1
      2
      3
      4
      5
      6
      @app.route('/get/<path:name>/')
      def get(name):
      print('----------')
      print(name)
      print(type(name))
      return '789'

      当输入url为http://127.0.0.1:5000/get/123/789/liangbo/heyingliang/得到:

      1
      2
      print(name)  # 123/789/liangbo/heyingliang
      print(type(name)) # <class 'str'>
    • uuid:
      验证uuid格式

    • any:

      1
      2
      3
      @app.route('/get/<any{c,d,e}:name>/')
      def get2(name):
      return '789'

      限定路径必须为下面其中之一 :
      /get/c/
      /get/d/
      /get/e/

  • 请求方法:

    Flask请求方法并不像Django一样全部支持的,需要自己配置请求方法:

    1
    2
    3
    @app.route('/get/name>/',methods=['GET','POST'])
    def index(name):
    return '789'

url for:
就是Flask的url反向解析

1
2
3
4
5
6
7
8
9
@app.route('/hello/')
def hello_world():
return render_template('hello.html')

@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
# 传入函数的名字作为url_for参数
url = url_for('hello_world')
return '789'

如果反向解析带有参数,直接传入关键字参数即可:

1
2
3
4
5
6
7
8
9
10
@app.route('/hello/<name1>/<name2>/')
def hello_world():
return render_template('hello.html')

@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
# 传入函数的名字作为url_for参数
url = url_for('hello_world',name1='hyl',name2='liangbo')
print(url) # /hello/hyl/liangbo/
return '789'

模板里的url反向解析,和Django差不多,不过使用url_for函数:

1
2
<!-- 传入hello_world视图函数 -->
<a href="{{ url_for('hello_world') }}"></a>

总结:

  • Django的反向解析:

    1. 视图里:

      1
      2
      def index(request):
      return reverse("blog:article", kwargs={"articleid": self.pk})
    2. 模板里:

      1
      <a href="{{ url blog:article self.pk }}"></a>
  • Flask的反向解析:

    1. 视图里:

      1
      2
      3
      4
      5
      6
      @app.route('/get/<path:name>/')
      def get(name):
      # 传入函数的名字作为url_for参数
      url = url_for('hello_world',name1='hyl',name2='liangbo')
      print(url) # /hello/hyl/liangbo/
      return '789'
    2. 模板里:

      1
      2
      <!-- 传入hello_world视图函数 -->
      <a href="{{ url_for('hello_world') }}"></a>

request:

在Django中,每个视图函数的第一个参数都是request,

1
2
3
4
5
def index(request):
'显示首页'
pageid = request.GET.get('page',1)
context = {...}
return render(request, 'blog/index.html', context)

但是在Flask中,已经封装好了,需要的话直接使用即可:

1
2
3
4
5
6
7
8
from flask import request


@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
print('----------------------------')
print(request) # <Request 'http://127.0.0.1:5000/get/123/' [GET]>
return '789'

request的属性:

  1. request.method

  2. request.data:

  3. request.args:
    get请求参数,不是只能用于get请求参数.

    例如,使用post提交http://127.0.0.1/article?cate=python一样可以获取

  4. request.form:
    post传递的表单数据

  5. request.files

  6. request.cookies

  7. request.session

  8. request.json
    如果提交的是json数据,可以这样直接转为json数据

  9. request.remote_addr
    远端的IP地址

  10. request.user_agent

  11. request.host

  12. request.url

如果传递的get参数中,有两个相同的参数,eg:

1
2
# 有两个kw参数
http://127.0.0.1/?kw=h&page&kw=yl

这时可以使用request.getlist('pw')获取两个pw参数


回头看一下这个视图函数:

1
2
3
4
5
@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
print('----------------------------')
print(request) # <Request 'http://127.0.0.1:5000/get/123/' [GET]>
return '789'

竟然可以返回string作为response,(而Django必须为HttpResponse)

实际上,Flask支持返回两个类型

  • 字符串
    (实际上Flask是后台帮我们包装成Response)

  • Response

1
2
3
4
5
6
@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
result = render_template('hello.html')
print(result)
print(type(result))
return result

返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang='cn'>

<head>
<meta charset="UTF-8">
<title>hello world</title>
<link rel="stylesheet" href="/static/css/hello.css">
</head>

<body>
<h2>hello world</h2>
<p>123</p>
</body>

</html>
<class 'str'>

说明result = render_template('hello.html')实际上就是渲染hello.html,然后返回一个字符串而已

所以我们可以直接返回一个string格式的html代码:

1
2
3
@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
return '<h3>响应</h3>'

实际上,当返回字符串时,视图函数还可以返回第二的值(响应状态码)

1
2
3
@app.route('/get/<path:name>/',methods=['GET','POST'])
def get(name):
return '<h3>响应</h3>',404

注意,这只会影响状态码,数据是不受影响的.
也就是说,就算上面返回了404错误,代码一样能跑,页面一样能显示

按照这种特性,我们可以用来做反爬.
(因为一般的爬虫只有当状态码为200的时候才会执行数据处理工作,404直接舍弃)

除了让Flask后台帮我们制作response,我们还可以使用make_response来制作response

1
2
3
4
5
6
@app.route('/get/',methods=['GET','POST'])
def get():
response = make_response('<h2>123</h2>')
print(response) # <Response 12 bytes [200 OK]>
print(type(response)) # <class 'flask.wrappers.Response'>
return response

所以也可以这么做:

1
2
3
4
5
6
@app.route('/get/',methods=['GET','POST'])
def get():
response = make_response(render_template('hello.html'),404)
print(response)
print(type(response))
return response

第二种手动制作Response的方法:使用Response

1
2
3
4
5
6
@app.route('/get/',methods=['GET','POST'])
def get():
response = Response(response='<h2>456</h2>',status=403)
print(response) # <Response 12 bytes [403 FORBIDDEN]>
print(type(response)) # <class 'flask.wrappers.Response'>
return response

重定向:
和Django差不多,一样使用redirect参数

1
2
3
@app.route('/get/',methods=['GET','POST'])
def get():
return redirect(url_for('index'))

遗弃request:
比如说在视图函数里判断是否为爬虫,如是则遗弃之:

1
2
3
4
5
@app.route('/get/',methods=['GET','POST'])
def get():
if ...:
abort(403)
return redirect(url_for('index'))

1560416151545

返回Json数据:
在Django里使用return JsonResponse来返回Json数据,Flask使用jsonfy:

1
2
3
4
5
6
7
8
from flask import json

@app.route('/get/',methods=['GET','POST'])
def get():
result = json.jsonify({'a':13,'b':45,'c':78})
print(result) # <Response 38 bytes [200 OK]>
print(type(result)) # <class 'flask.wrappers.Response'>
return result

1560416397738

注意:jsonify可以传入字典,也可以使用关键字参数

1
2
result = json.jsonify({'a':13,'b':45})
result = json.jsonify(a=18,b=20)

其实也可以使用

1
2
3
4
# 注意不是import json
from flask import json

result = json.dumps({'a':13,'b':45})

注意json.jsonifyjson.dumps的异同:

两者都会将数据格式化为Json格式

  • 使用json.jsonify会自动将response的content-Type改为application/json.
  • json.dumps将保留原来的content-Type为text/html不变

当然,这还是有解决方法的:使用Response:

1
2
3
4
@app.route('/get/',methods=['GET','POST'])
def get():
result = json.dumps({'a':18,'b':20})
return Response(response=result,content_type='application/json')

实际上,Flask在真正开发的时候,文件结构和Django还是差不多的

1
2
3
4
5
6
7
8
9
10
webproject
|-- app
|-- models.py
|-- views.py
|-- static
|-- css
|-- js
|-- templates
|-- hello.html
|-- manage.py

可见,在Flask中,其实Views基本就是Django里Views和urls.py的合并

但是如果我们像上面这样存放文件,app.views会和manage.py循环引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# manage.py
from flask import Flask
from flask_script import Manager
# 因为manage.py是整个程序的入口,执行python manage.py,所以必须在这里导入views.py
# 这里使用一个a表示导入views
from app.views import a

print(a)

app = Flask(__name__)

manager = Manager(app=app)


if __name__ == '__main__':
manager.run()
1
2
3
4
5
6
7
8
9
10
# app/views.py

# 要想使用@app.route('/')装饰器,必须导入manage.py里的app
from manage import app

a = 10

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

问题就出在两个import中:
我们在运行manage.py的时候会执行from app.views import a,这句会让python去扫描app/views.py.但是在app/views.py中又有from manage import app这句又会让python去扫描manage.py

1560425361671

也就是说出现了互相导入的问题:

1560425600067

这时可以使用插件解决:
蓝图:支持对程序的规划

简单来说就是使用蓝图来代替@app.route(),使得view.py不再依赖manage.py

1
pip install flask-blueprint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# manage.py
from flask import Flask
from flask_script import Manager

from app.views import blue

app = Flask(__name__)
# 注册蓝图
app.register_blueprint(blueprint=blue)

manager = Manager(app=app)


if __name__ == '__main__':
manager.run()
1
2
3
4
5
6
7
8
9
# app/views.py
from flask import Blueprint

blue = Blueprint('first_blue',__name__)

# 从app.route改为blue.route
@blue.route('/')
def index():
return 'index'

1560426367170

所以我们就可以使用多个views.py文件了:

1
2
3
4
5
6
7
8
9
# view.py
from flask import Blueprint


blue = Blueprint('first_blue',__name__)

@blue.route('/')
def index():
return 'index'
1
2
3
4
5
6
7
8
9
# view2.py
from flask import Blueprint


blue2 = Blueprint('second_blue',__name__)

@blue2.route('/index2/')
def index2():
return 'index2'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# manage.py
from flask import Flask
from flask_script import Manager

from app.views import blue
from app.views2 import blue2

app = Flask(__name__)
# 注册蓝图
app.register_blueprint(blueprint=blue)
app.register_blueprint(blueprint=blue2)

manager = Manager(app=app)


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

1560430361202

1560430351185


会话技术:
三种会话技术:

  • cookies:

    1. 客户端会话技术
    2. 数据都是存储在浏览器中
    3. 支持过期
    4. 不能跨域名
    5. 不能跨浏览
    6. cookie是通过 Response来进行操作

    flask中的cookie可以支持中文
    因为flask对cookie中的内容作了编码

  • session

    1. 服务端会话技术
    2. 对数据进行数据安全操作
    3. 默认在内存中
      • 不容易管理
      • 容易丢失
      • 不能多台电脑协作
      • flask-session默认的有效期是31天
  • token

简单cookie的登录注册功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# view.py
@blue.route('/home/')
def home():
username = request.cookies.get('user')
return render_template('home.html',username=username)

@blue.route('/login/',methods=['GET','POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
resp = Response(response= f'登录成功 {username}')
resp.set_cookie('user',username)
return resp

@blue.route('/logout/')
def logout():
resp = redirect(url_for('first_blue.home'))
resp.delete_cookie('user')
return resp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- home.html -->
<!DOCTYPE html>
<html lang='cn'>

<head>
<meta charset="UTF-8">
<title>home</title>
</head>

<body>
<h2>欢迎回来:{{ username }}</h2>
<a href="{{ url_for('first_blue.login') }}">登录</a>
<a href="{{ url_for('first_blue.logout') }}">登出</a>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- login.html -->
<!DOCTYPE html>
<html lang='cn'>

<head>
<meta charset="UTF-8">
<title>login</title>
</head>

<body>
<form action="{{ url_for('first_blue.login') }}" method="post">
<span>用户名:</span><input type="text" name="username" placeholder="请输入用户名" />
<br />
<input type="submit"/>
</form>
</body>

</html>

如果要将cookie改为session:不能像Django一样直接改动request.cookies.get(‘user’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@blue.route('/home/')
def home():
# username = request.cookies.get('user')
username = session.get('user')
return render_template('home.html',username=username)


@blue.route('/login/',methods=['GET','POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
resp = Response(response= f'登录成功 {username}')
session['user'] = username
# resp.set_cookie('user',username)
return resp

1560436785333

还需要在manage里配置SECRET_KEY:

1
app.config['SECRET_KEY'] = '1234liangbo5679'

flask-session插件

1
pip install flask-session

使用,首先在manage.py里添加config设置

1
2
app.config['SESSION_TYPE'] = 'redis'
Session(app=app)

这样我们就将session储存到redis中了:
1560437968715

flask-session默认的有效期是31天


模板

路由器装饰器的叠用:这样这个视图函数就可以由多个路由url来调用

1
2
3
4
5
@blue.route('/home/')
@blue.route('/index/')
@blue.route('/')
def logout():
return render_tempalte('hello.html')

Fask中使用jinja2模板引擎

jinja2模板语法和Django差不多
(因为是在DJango模板的基础上改的)

jinja2可以使用

  • 变量 :{{ var }}
  • 标签 :{{ tag }}

jinja2一样支持block和extends标签:

1
2
3
# 父模板挖坑,子模板填坑
{% block 'xxx' %}
{% endblock %}
1
2
3
4
5
# 继承模板
{% extend 'xxx' %}

# 继承后保留块中的内容
{{ super() }}

保留继承块中的内容:{{ super() }}
Django中用是{{ block.super }}

eg:base.html中有

1
2
3
{% block header %}
<h2>this is base html</h2>
{% endblock %}

index.html中有:

1
2
3
4
5
{% extends 'base.html' %}

{% block header %}
<h2>this is index html</h2>
{% endblock %}

这时index.html中的h2会覆盖掉base.html中的h2,

1560475321878

现在想要双方都显示:

1
2
3
4
5
6
{% extends 'base.html' %}

{% block header %}
{{ super() }}
<h2>this is index html</h2>
{% endblock %}

1560475338999

Flask的Static静态文件的反向解析:

1
2
3
{% block extcss %}
<link rel="stylesheet" href="{{ url_for('static',filename='css/hello.css') }}">
{% endblock extcss %}

Flask中的inclue标签和Django的差不多,功能就是将其他的html包含进来


marco:宏定义
可以在模板中定义函数,在其他的地方调用,调用函数来生成html.

1
2
3
{% marco hello(name) %}
{{ name }}
{% endmarco %}

例如:

1
2
3
4
5
6
7
{# 定义 #}
{% macro hello() %}
<h4>该函数调用就能产生html代码</h4>
{% endmacro %}

{# 调用 #}
{{ hello() }}
1
2
3
4
5
6
7
8
{# 定义 #}
{% macro say_hello(name,age) %}
<h4>很高兴见到你 {{ name }}</h4>
<h4>听说你今年 {{ age }} 岁了</h4>
{% endmacro %}

{# 调用 #}
{{ say_hello('何应良',21) }}

可以导入其他页面的宏定义:

1
{% from 'xxx' import xxx %}

示例:

1
2
{% from 'mac.html' import say_hello %}
{{ say_hello('何应良',21) }}

jinja2也可以使用Django的控制语句(for if等等),过滤器
多个过滤器注意safe的顺序:

1
2
3
4
<h3>{{ msg|safe|reverse }}</h3>

{# 输出 #}
>2h<啊戏游啥玩们你>2h<

虽然safe放在前面,但是safe永远都是最后执行的,也就是说,会先执行reverse


反向解析总结:

  1. url_for
  2. 在app中使用:
    • url_for(‘endpoint)
    • endpoint默认是函数的名字
  3. 在blueprint中使用:
    • url_for(‘bluename.endpoint’)
    • 蓝图名字.函数名
  4. 获取静态资源路径:
    • url_for(‘static’,filename=’path’)
    • static:资源
    • path:相对资源的相对路径

四个结构标签:

  • block
  • extends
  • include
  • marco

使用flask-bootstrap插件:

使用Bootstrap 来美化页面

1
pip install flask-bootstrap

在manage.py添加配置:

1
2
from flask_bootstrap import Bootstrap
Bootstrap(app=app)

使用:

1
2
3
@blue.route('/test_bootstrap/')
def test_bootstrap():
return render_template('test_bootstrap.html')
1
2
3
4
5
6
{# test_bootstrap #}
{% extends 'bootstrap/base.html' %}

{% block content %}
<h3>这是一个bootstrap</h3>
{% endblock content %}

1560480529388


会话技术总结:

  1. 出现的场景:
    后续的请求要前面请求返回的数据

  2. 原因:
    web开发中,使用的http基本都是短连接.
    生命周期非常短,从Request开始到Response结束

  3. 实现机制:
    让客户端知道自己是谁

  4. cookies:
    客户端会话技术,数据都存储在客户端中,浏览器中.
    特性:

    • 存储结构key-value,
    • 支持过期时间:max-age,expires
    • 不能跨域名,不能跨浏览器,默认会携带本网站的所有cookies,
    • 默认明文传输,默认不支持中文(Flask可以支持中文)
  5. session:
    服务端会话技术,数据存储在服务端 .
    特性:

    • 依赖于cookie
    • 支持过期
    • key-value存储结构
    • session在flask默认没有实现持久化

    实现持久化:flask-session

  6. token:

    • 服务端会话技术
    • 手动实现的session
    • 如果用在web中和session基本一致
    • 在专用客户端中,不支持cookie
    • 需要客户端自己为何token

消息闪现flash:

  • 在视图中使用flash('message')
  • 在template中使用get_flash_messages()

Flask模型

Flask默认并没有提供任何数据库操作的API

python有一个ORM:SQLAlchemy.

针对Flask的支持插件flask-sqlalchemy:

1
pip install flask-sqlalchemy

数据库连接:

1
dialect+driver: //username:password@host:port/database

dialect:数据库实现
driver:数据库的驱动

在manage.py里配置:

1
2
3
4
5
6
7
8
# manage.py
from app.models import init_db


app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sqlite3.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

init_db(app)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# views.py
from app.models import db,Preson


# 添加数据库
@blue.route('/createdb/')
def create_db():
db.create_all()
return 'DB Create Success'

@blue.route('/addperson/')
def add_person():
p = Person()
p.p_name = 'liangbo'
db.session.add(p)
db.session.commit()
return 'Person Add Success'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# models.py
from flask_sqlalchemy import SQLAlchemy


db = SQLAlchemy()

# 定义成函数,使用懒加载,避免循环引用
def init_db(app):
db.init_app(app)


class Preson(db.Model):
p_id = db.Column(db.Integer,primary_key=True,autoincrement=True)
p_name= db.Column(db.String(16))

定义的这么复杂就是为了避免循环引用的问题:
1560497120288

当然上面把船创建数据库都制作成一个url,一般我们都是在shell里手动创建数据库的.
在shell里执行db.create_all()即可.

数据库查询:

1
2
3
4
5
# views.py
@blue.route('/getperson/')
def get_person():
persons = Person.query.all()
return render_template('personlist.html',person=persons)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang='cn'>

<head>
<meta charset="UTF-8">
<title>personlist</title>
</head>

<body>
<ul>
{% for person in persons %}
<li>{{ person.p_name }}</li>

{% endfor %}
</ul>
</body>

</html>

如果要使用mysql的话:

1
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sqlite3.db'

改为

1
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql:///用户名:密码@主机:端口/数据库名'