头图:https://cdn.naraku.cn/imgs/flask-0.jpg
摘要:简单学了一点Flask基础,记录一下。
Flask基础
- 传值总结:https://blog.csdn.net/MooKee_cc/article/details/52947332
命令行启动
$ flask run --port=8080
运行过程
- 客户端向服务器发起请求
- 服务器把请求交给Flask实例
- Flask实例通过
Werkzeug
根据URL请求与视图函数之间的对应关系来进行路由分发 - 根据每个URL请求,找到具体的视图函数并进行调用
- Flask程序中路由一般是通过程序实例的装饰器实现
- Flask调用视图函数后,可以返回2种内容:
- 新建一个Flask项目
导入Flask类
# 导入Flask
from flask import Flask
创建实例。需要传入一个参数
name
,指向程序所在的模块app = Flask(__name__)
配置路由。通过装饰器将路由映射到视图函数
@app.route('/')
def index():
return 'Hello World!'
完整代码 ```python
-- coding:utf-8 --
导入Flask
from flask import Flask
创建实例
app = Flask(name)
路由与视图函数对应关系
@app.route(‘/‘) def index(): return ‘Hello World!’
启动程序
if name == ‘main‘: app.run()
<a name="75fc7de7"></a>
## 路由
<a name="3b4c5cab"></a>
### 请求方式
- 使用`methods`参数指定可接受的请求方式,可指定多种,默认只接受`GET`请求
```python
@app.route('/', methods=['GET','POST'])
def hello():
return 'Hello'
参数处理
有时候需要将同一类URL映射到同一个视图函数处理,例如某个分类下不同的图书返回不同信息
- 使用
<>
定义路由动态参数 - 并且将该参数传入视图函数
@app.route('/code/<book_id>')
def book(book_id):
print(type(book_id)) # 默认是str
return f'当前书本ID为: {book_id}'
- 使用
有时候需要对路由做访问优化。例如上面的
book_id
应是int
类型- 只需要在
<>
中的变量名前加上指定类型:
即可 - 若指定为
int
类型,则访问/code/abc
等str
类型的路由时会返回404 Not Found
@app.route('/code/<int:book_id>')
def book(book_id):
print(type(book_id)) # 此时为int
return f'当前书本ID为: {book_id}'
- 只需要在
模板引擎
视图函数的作用有2个:处理业务逻辑和内容。
- 模板其实是一个包含响应文本的文件,用变量表示动态部分,告诉模板引擎其具体的值需要从使用的数据中获取
- 使用真实值替换变量,再返回最终的字符串,这个过程称为渲染。Flask使用模板引擎
Jinja2
来渲染模板
返回HTML
- 前面都是写如何返回字符串,那么如果需要返回HTML模板,则可以通过
render_template
实现
app = Flask(name)
@app.route(‘/‘) def index(): return render_template(‘index.html’) # templates目录下的index.html
if name == ‘main‘: app.run()
<a name="457a9254"></a>
### 动态渲染
- 如果需要在模板中使用某些动态的参数,则需要在视图函数中传递参数
- 视图函数中通过`render_template()`函数传参
- HTML模板文件中通过`{{}}`使用该变量
```python
@app.route('/')
def index():
url = "www.naraku.cn"
return render_template('index.html', url=url)
index.html
:<h1>欢迎来到: {{ url }}</h1>
用法
注释:
{# #}
{# 这是注释 #}
{# {{name}} #}
控制:
{% %}
```html {% if id>50 %} {{id}} => 大于50 {% elif id<50 %} {{id}} => 小于50 {% else %} {{id}} => 等于50 {% endif %}
{% for num in nums %}
当前数字为: {{num}}
{% endfor %}
- 举个例子
```python
def index():
id = 100
nums = [1, 2, 3, 4, 5]
return render_template('index.html', id=id, nums=nums)
index.html
{% if id>50 %}
<h1>id为: {{id}} => 大于50</h1>
{% elif id<50 %}
<h1>id为: {{id}} => 小于50</h1>
{% else %}
<h1>id为: {{id}} => 等于50</h1>
{% endif %}
{# 注释: 上面是if,下面是for #}
{% for num in nums %}
<p>当前数字为: {{num}}</p>
{% endfor %}
过滤器
- 过滤器的本质是函数,有时候不仅仅只是需要输出变量的值,还需要修改变量的显示,甚至格式化、运算等等,而在模板中是不能直接调用Python中某些方法的,那么就用到了过滤器
使用方式:
过滤器的使用方式:
变量名 | 过滤器
{{ name | filter(*args) }}
如果没有任何参数传给过滤器,可以省略括号
{{ name | filter }}
举个例子
@app.route('/')
def index():
name = "naraku"
return render_template('index.html', name=name)
{# 字符串变大写 #}
<p>{{ name | upper }}</p>
链式调用
Jinja2
中,过滤器支持链式调用,从左到右按顺序执行
<p>{{ 'Hello World' | upper | reverse }}</p>
常用过滤器
format
:格式化输出<p>{{ '%s' | format(name) }}</p>
safe
:禁用转义<p>{{ '<em>hello</em>' | safe }}</p>
capitalize
:首字母大写,其余小写<p>{{ 'hello' | capitalize }}</p>
upper/lower
:全部转为大写或小写 ```html{{ ‘Hello World’ | lower }}
{{ ‘Hello World’ | upper }}
- `reverse`:字符串反转
```html
<p>{{ 'Hello World' | reverse }}</p>
truncate
:字符串截断<p>{{ 'hello world' | truncate(3) }}</p>
striptags
:渲染前把所有HTML标签删除<p>{{ '<em>hello</em>' | striptags }}</p>
Web表单
Web表单是Web程序的基本功能,它是HTML页面中负责数据采集的部件。表单中有三部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。
简单示例
视图函数
路由需要有
GET
和POST
请求,需要判断请求方式- 路由中添加参数
methods
,以列表的方式传入请求方式GET
和POST
引入
request
对象,获取请求方式及参数@app.route("/", methods=['GET', 'POST'])
def index():
# 获取请求方式
if request.method == "POST":
# 获取请求参数
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
# 判断参数是否完整
if not all([username, password, password2]):
print("参数不完整")
elif password != password2:
print("密码不一致")
else:
return "success"
return render_template("index.html")
- 路由中添加参数
模板文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WTF</title>
</head>
<body>
<form method="post">
<label>用户名:</label><input type="text" name="username"><br>
<label>密码:</label><input type="password" name="password"><br>
<label>确认密码:</label><input type="password" name="password2"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
Flash消息闪现
- 有时候需要向模板动态传递一些消息,例如提示用户名不能为空、密码不一致等等,可以通过
flash
库实现- 引入
flash
库 - 设置密钥
Secret_key
```python from flask import Flask, render_template, request, flash
- 引入
app = Flask(name)
@app.route(“/“, methods=[‘GET’, ‘POST’]) def index(): if request.method == “POST”: username = request.form.get(‘username’) password = request.form.get(‘password’) password2 = request.form.get(‘password2’)
# 向模板传递消息
if not all([username, password, password2]):
flash("参数不完整")
elif password != password2:
flash("密码不一致")
else:
return "success"
return render_template("index.html")
if name == ‘main‘: app.run()
- 模板文件通过`get_flashed_messages()`函数获取消息并渲染
```html
<body>
<form method="post">
<label>用户名:</label><input type="text" name="username"><br>
<label>密码:</label><input type="password" name="password"><br>
<label>确认密码:</label><input type="password" name="password2"><br>
<input type="submit" value="提交"><br>
{# 通过遍历函数获取消息 #}
{% for msg in get_flashed_messages() %}
{{ msg }}
{% endfor %}
</form>
</body>
- 此时直接启动程序,会出现报错,原因是因为未设置密钥
Secret_key
flash
希望对需要输出的内容进行加密,因此需要设置密钥,作加密消息的混淆。- 只需要一行代码,给
app.secret_key
赋值即可 ```python from flask import Flask, render_template, request, flash
- 只需要一行代码,给
app = Flask(name) app.secret_key = “naraku” # 设置密钥
….
- 如果使用**Python2**进行开发,可能会遇到`UnicodeDecodeError`等编码的问题,只需要在中文字符前面加个`u`进行转码即可
```python
@app.route("/", methods=['GET', 'POST'])
def index():
if request.method == "POST":
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
# 向模板传递消息
if not all([username, password, password2]):
flash(u"参数不完整") # 这里加个u
elif password != password2:
flash(u"密码不一致")
else:
return "success"
return render_template("index.html")
过滤
- 有时需要在不同的地方显示不同信息
flash()
接收2个参数,通过指定第2个参数category
,并在前端通过category_filter=["分类名"]
过滤调用if open_form.submit.data and open_form.validate_on_submit():
pill_key = request.form.get('pill_key')
flash(f"Open表单提交成功: {pill_key}", category="open")
elif find_form.submit.data and find_form.validate_on_submit():
find_email = request.form.get('find_email')
flash(f"Find表单提交成功: {find_email}", category="find")
{% for msg in get_flashed_messages(category_filter=["find"]) %}
{{ msg }} <br>
{% endfor %}
插件-表单-WTF
在Flask中,为了处理Web表单,一般使用Flask-WTF
扩展,它封装了WTForms
,并且验证表单数据的功能。
- 使用
Flask-WTF
需要配置密钥参数SECRET_KEY
,必须开启**CSRF_token**
CSRF_ENABLED
可以防止CSRF,SECRET_KEY
用于生成加密令牌。CSRF防护会根据设置的密钥生成加密令牌- 需要先安装此插件
pip install Flask-WTF
基本示例
- 先自定义一个表单类
- 继承自基类
FlaskForm
- 导入所需的表单字段 ```python from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField
- 继承自基类
app = Flask(name) app.secret_key = “naraku”
class RegForm(FlaskForm): username = StringField(“账号:”) password = PasswordField(“密码:”) password2 = PasswordField(“确认密码:”) submit = SubmitField(“提交”)
- 传递到模板
```python
@app.route("/reg", methods=['GET', 'POST'])
def reg():
reg_form = RegForm()
return render_template("index.html", reg_form=reg_form)
前端渲染
<body>
<form method="post">
{{ reg_form.username.label }} {{ reg_form.username }} <br>
{{ reg_form.password.label }} {{ reg_form.password }} <br>
{{ reg_form.password2.label }} {{ reg_form.password2 }} <br>
{{ reg_form.submit }}
</form>
</body>
完整代码 ```python
-- coding:utf-8 --
from flask import Flask, render_template, request, flash from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField
app = Flask(name) app.secret_key = “naraku”
class RegForm(FlaskForm): username = StringField(“账号:”) password = PasswordField(“密码:”) password2 = PasswordField(“确认密码:”) submit = SubmitField(“提交”)
@app.route(“/reg”, methods=[‘GET’, ‘POST’]) def reg(): reg_form = RegForm() return render_template(“index.html”, reg_form=reg_form)
if name == ‘main‘: app.run()
<a name="6cc7dc63"></a>
### 表单验证
- 引入验证函数,并在表单类中实现
- **必须开启**`**CSRF_token**`,否则验证失败
- 通过`validators`传递需要调用的函数,可以为一个列表
- `DataRequired()`,判断字段是否非空
- `EqualTo()`,判断当前字段与目标字段是否相等。第1个参数为目标字段,第2个参数为错误消息
```python
from wtforms.validators import DataRequired, EqualTo
class RegForm(FlaskForm):
username = StringField("账号:", validators=[DataRequired()])
password = PasswordField("密码:", validators=[DataRequired()])
password2 = PasswordField("确认密码:", validators=[DataRequired(), EqualTo("password", "密码不一致")])
submit = SubmitField("提交")
表单验证
- 通过
表单对象.validate_on_submit()
函数一行实现表单验证 ```python @app.route(“/reg”, methods=[‘GET’, ‘POST’]) def reg(): reg_form = RegForm() # 创建一个表单对象
获取请求方式
if request.method == “POST”:
获取请求参数
username = request.form.get(‘username’) password = request.form.get(‘password’) password2 = request.form.get(‘password2’)
表单验证
if reg_form.validate_on_submit():
return "Success"
else:
pass
return render_template(“index.html”, reg_form=reg_form) ```
- 通过
前端开启
CSRF_token
通过调用
对象名.csrf_token()
函数开启<body>
<form method="post">
{# 开启CSRF_token #}
{{ reg_form.csrf_token() }}
{{ reg_form.username.label }} {{ reg_form.username }} <br>
{{ reg_form.password.label }} {{ reg_form.password }} <br>
{{ reg_form.password2.label }} {{ reg_form.password2 }} <br>
{{ reg_form.submit }}<br>
{# Flash消息 #}
{% for msg in get_flashed_messages() %}
{{ msg }}
{% endfor %}
</form>
</body>
完整代码 ```python
-- coding:utf-8 --
from flask import Flask, render_template, request, flash from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, EqualTo
app = Flask(name) app.secret_key = “naraku”
class RegForm(FlaskForm): username = StringField(“账号:”, validators=[DataRequired()]) password = PasswordField(“密码:”, validators=[DataRequired()]) password2 = PasswordField(“确认密码:”, validators=[DataRequired(), EqualTo(“password”, “密码不一致”)]) submit = SubmitField(“提交”)
@app.route(“/reg”, methods=[‘GET’, ‘POST’]) def reg(): reg_form = RegForm()
# 获取请求方式
if request.method == "POST":
# 获取请求参数
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
# 表单验证
if reg_form.validate_on_submit():
return "success"
else:
flash("参数有误")
return render_template("index.html", reg_form=reg_form)
if __name__ == '__main__':
app.run(debug=True)
<a name="1936afac"></a>
### 常用字段
| 字段对象 | 说明 |
| --- | --- |
| StringField | 文本字段 |
| TextAreaField | 多行文本字段 |
| PasswordField | 密码字段 |
| HiddenField | 隐藏文件字段 |
| DateField | 文本字段,值为 `datetime.date`<br /> 文本格式 |
| DateTimeField | 文本字段,值为 `datetime.datetime`<br /> 文本格式 |
| IntegerField | 文本字段,值为整数 |
| DecimalField | 文本字段,值为`decimal.Decimal` |
| FloatField | 文本字段,值为浮点数 |
| BooleadnField | 复选框,`True`<br />/`False` |
<a name="6114e108"></a>
### 常用验证函数
| 验证函数 | 说明 |
| --- | --- |
| `DataRequired` | 确保字段中有数据 |
| `EqualTo` | 比较两个字段的值,常用于判断两次密码是否一致 |
| `Length` | 验证输入的字符串长度 |
| `NumberRange` | 验证输入的数值范围 |
| `URL` | 验证URL |
| `AnyOf` | 验证输入值在可选列表中 |
| `NoneOf` | 验证输入值不在可选列表中 |
<a name="cc09f939"></a>
## 插件-数据库-SQLAlchemy
- `SQLAlchemy`是一个关系型数据库框架,它提供了高层ORM和底层的原生数据库操作,`Flask-sqlalchemy`是一个简化了的`SQLAlchemy`操作的扩展。`SQLAchemy`实际上是对数据库的抽象,让开发者不用直接和SQL语句打交道,而是通过Python对象来操作数据库。
- 安装`Flask-sqlalchemy`
```shell
pip install flask-sqlalchemy
- 如果需要操作Mysql,还需要安装
mysqldb
pip install flask-mysqldb
管理数据库
在
Flask-SQLAlchemy
中,数据库使用URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI
键中数据库类型://数据库账号:密码@地址:端口/数据库名
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:root@127.0.0.1:3306/flask'
其它设置
# 动态追踪修改设置,如未设置只会提示警告,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
创建数据库对象
- 引入相关库,配置app对象的数据库信息,创建数据库对象,并传入当前app对象 ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy
app = Flask(name) app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘mysql://root:root@127.0.0.1:3306/flask_demo’ app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False db = SQLAlchemy(app)
- 创建一个数据库,打开命令行登录数据库后输入
```sql
create database flask_demo charset=utf8;
数据模型
- 定义数据模型
| Roles表 | |
| —- | —- |
|
role_id(
主键) | | | 1 | 管理员 | | 2 | 普通用户 |
Users表 | ||
---|---|---|
user_id |
user_name |
role_id (外键) |
1 | 1号管理 | 1 |
2 | 2号管理 | 1 |
3 | 用户A | 2 |
- 实现数据模型
class User(db.Model): tablename = ‘users’ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True) role_id = db.Column(db.Integer, db.ForeignKey(‘roles.id’)) # 外键
- 创建表
```python
if __name__ == '__main__':
# db.drop_all() # 删除表
db.create_all() # 新建表
# app.run()
基本操作
- 增删改操作,由数据库会话
db.session
管理- 在准备把数据写入数据库前,要先将数据添加到会话中,然后调用
db.session.commit()
方法提交会话
- 在准备把数据写入数据库前,要先将数据添加到会话中,然后调用
- 查询操作,通过
query
对象进行操作- 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询
增删改
if __name__ == '__main__':
# db.drop_all() # 删除表
# db.create_all() # 新建表
# 增加
# Role表增加用户
role = Role(name='admin') # 创建一个对象
db.session.add(role) # 将添加对象加入会话
db.session.commit() # 将会话提交到数据库
# User表增加用户
# 此时role对象的id为1,所以创建的user是管理员权限
user = User(name='naraku', role_id=role.id)
db.session.add(user)
db.session.commit()
# app.run()
# 修改
# 前面已经把user对象添加到db.session()中,因此不需要再次添加
user.name = 'miroku'
db.session.commit()
# 删除
db.session.delete(user)
db.session.commit()
- 其它语句
db.session.add(role) # 添加到数据库的session中
db.session.add_all([user1, user2]) # 以列表形式添加多个
db.session.rollback() # 回滚操作
db.session.delete(user) # 删除数据
db.session.commit() # 提交到数据库
查询
简单应用
from flask import Flask from flask_sqlalchemy import SQLAlchemy
app = Flask(name) app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘mysql://root:root@127.0.0.1:3306/flask_demo’ app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False db = SQLAlchemy(app)
class Role(db.Model): tablename = ‘roles’ id = db.Column(db.Integer, primary_key=True) # 主键 name = db.Column(db.String(16), unique=True) # 唯一 users = db.relationship(‘User’, backref=’role’)
class User(db.Model): tablename = ‘users’ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True) email = db.Column(db.String(16), unique=True) role_id = db.Column(db.Integer, db.ForeignKey(‘roles.id’)) # 外键
def __repr__(self):
return f'<User: {self.id}, {self.name}, {self.email}>'
@app.route(‘/‘) def index(): return ‘Hello SQLAlchemy’
if name == ‘main‘: db.drop_all() # 删除表 db.create_all() # 新建表
Role表
role1 = Role(name='Admin') # 管理员
role2 = Role(name='Guest') # 普通用户
db.session.add_all([role1, role2])
db.session.commit()
# User表
user1 = User(name='naraku',email='naraku@qq.com' , role_id=role1.id)
user2 = User(name='zhang',email='zhang@qq.com' , role_id=role2.id)
user3 = User(name='chen',email='chen@qq.com' , role_id=role2.id)
user4 = User(name='zhou',email='zhou@qq.com' , role_id=role2.id)
user5 = User(name='tang',email='tang@qq.com' , role_id=role2.id)
user6 = User(name='wu',email='wu@qq.com' , role_id=role2.id)
user7 = User(name='qian',email='qian@qq.com' , role_id=role2.id)
user8 = User(name='liu',email='liu@qq.com' , role_id=role2.id)
user9 = User(name='li',email='li@qq.com' , role_id=role2.id)
user10 = User(name='sun',email='sun@qq.com' , role_id=role2.id)
db.session.add_all([user1, user2, user3, user4, user5, user6, user7, user8, user9, user10])
db.session.commit()
![](https://cdn.nlark.com/yuque/0/2020/jpeg/520228/1608494105482-e69bfa7b-6594-4c38-b999-5237258eb6ee.jpeg#crop=0&crop=0&crop=1&crop=1&height=654&id=uf0M2&originHeight=654&originWidth=1241&originalType=binary&ratio=1&rotation=0&showTitle=false&size=0&status=done&style=none&title=&width=1241)
- 这里借助`ipython`这个库,可以直接在`Pycharm`下方的`Terminal`终端调用进行查询。如果没有`ipython`的可通过`File-> setting-> Project Interpreter`进行安装
- 安装完成后在`Terminal`输入`ipython`进入,并导入当前文件全部代码
```shell
> ipython
IN [1]: from demo import *
查询id为4的用户
因为id是主键,可通过执行器get查询
User.query.get(4)
通过过滤器查询
User.query.filter_by(id=4).first() User.query.filter(User.id==4).first()
![](https://cdn.nlark.com/yuque/0/2020/jpeg/520228/1608494105483-82e4da74-9b7d-4deb-9c3b-ebdafb1f1bd1.jpeg#crop=0&crop=0&crop=1&crop=1&height=878&id=hurPu&originHeight=878&originWidth=1373&originalType=binary&ratio=1&rotation=0&showTitle=false&size=0&status=done&style=none&title=&width=1373)
<a name="cc525323"></a>
##### 查询执行器
`表模型名.query.方法()`
| 方法 | 说明 |
| --- | --- |
| `all()` | 以列表形式返回查询的所有结果 |
| `first()` | 返回查询的第一个结果,如未查到,返回None |
| `first_or_404()` | 返回查询的第一个结果,如未查到,返回404 |
| `get()` | 返回指定主键对应的行,如不存在,返回None |
| `get_or_404()` | 返回指定主键对应的行,如不存在,返回404 |
| `count()` | 返回查询结果的数量 |
| `paginate()` | 返回一个Paginate对象,它包含指定范围内的结果 |
<a name="333bd245"></a>
##### 查询过滤器
| 过滤器 | 说明 |
| --- | --- |
| `filter(对象.属性==值)` | 把过滤器添加到原查询上,返回一个新查询。支持比较运算符 |
| `filter_by(属性=值)` | 把等值过滤器添加到原查询上,返回一个新查询 |
| `limit` | 使用指定的值限定查询返回结果 |
| `offset()` | 偏移原查询返回的结果 |
| `order_by()` | 根据指定条件对原查询进行排序,返回一个新查询 |
| `group_by()` | 根据指定条件对原查询进行分组,返回一个新查询 |
<a name="69851aa1"></a>
### 关系引用
有时候需要一些属性方便查询数据,但是这些属性不能出现在数据库的字段中
- `relationship()`:`sqlalchemy`对关系之间提供的一种便利的调用方式,关联不同的表
- 第1个参数:对象模型名。指需要关联的对象,可在`Role`类的实例中通过`role.users`查看该实例在`User`模型中的属性
- `backref`参数:对关系提供**反向引用**的声明。可在`User`类的实例中通过`user.role`查看该实例在`Role`模型中的属性
```python
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True) # 主键
name = db.Column(db.String(16), unique=True) # 唯一
# 关键代码
users = db.relationship('User', backref='role')
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(16), unique=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) # 外键
- 完整代码
__repr__(self)
:输出某个实例化对象时的回显 ```python from flask import Flask from flask_sqlalchemy import SQLAlchemy
app = Flask(name) app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘mysql://root:root@127.0.0.1:3306/flask_demo’ app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False db = SQLAlchemy(app)
class Role(db.Model): tablename = ‘roles’ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(16), unique=True)
# 关键代码
users = db.relationship('User', backref='role')
def __repr__(self):
return f'<Role: {self.name}, {self.id}>'
class User(db.Model):
tablename = ‘users’
id = db.Column(db.Integer, primarykey=True)
name = db.Column(db.String(16), unique=True)
roleid = db.Column(db.Integer, db.ForeignKey(‘roles.id’)) # 外键
def __repr(self):
return f’
@app.route(‘/‘) def index(): return ‘Hello SQLAlchemy’
if name == ‘main‘: db.drop_all() # 删除表,防止测试时数据冗余 db.create_all() # 新建表 role = Role(name=’admin’) db.session.add(role) db.session.commit()
user1 = User(name='naraku', role_id=role.id)
user2 = User(name='miroku', role_id=role.id)
db.session.add_all([user1, user2])
db.session.commit()
print(role.users) # 查看Role实例在User表中的属性
print(user1.role) # 查看User实例在Role表中的属性
print(user2.role)
<a name="0613b887"></a>
### 常见字段
- `db.字段名`
| 类型名 | Python数据类型 | 说明 |
| --- | --- | --- |
| `Integet` | `int` | 普通整数,一般是32位 |
| `SmallInteget` | `int` | 取值范围小的整数,一般是16位 |
| `BigInteget` | `int/long` | 不限制精度的 |
| `Float` | `float` | 浮点数 |
| `Numeric` | `decimal.Decimal` | 普通整数,一般是32位 |
| `String` | `str` | 变长字符串 |
| `Text` | `str` | 变长字符串,对较长或不限长度的字符串做了优化 |
| `Unicode` | `unicode` | 变长Unicode字符串 |
| `UnicodeText` | `unicode` | 变长Unicode字符串,对较长或不限长度的字符串做了优化 |
| `Boolean` | `bool` | 布尔值 |
| `Date` | `datetime.date` | 时间 |
| `Time` | `datetime.datetime` | 日期和时间 |
| `LargeBinary` | `str` | 二进制文件 |
<a name="b043fc3a"></a>
### 常见列选项
| 选项名 | 说明 |
| --- | --- |
| `primary_key` | 主键。若为`True`<br />,即为表的主键 |
| `unique` | 唯一。若为`True`<br />,即此列不允许出现重复的值 |
| `default` | 默认值。为此列定义默认值 |
| `index` | 索引。若为`True`<br />,为此列创建索引,提高查询效率 |
| `nullable` | 非空。若为`True`<br />,允许为空,反之不允许为空 |
<a name="a8d14911"></a>
## 依赖包
```shell
$ pip freeze > requirements.txt # 输出依赖包及版本到文本
$ pip install -r requirements.txt # 安装依赖包