Flask基础
- 传值总结:https://blog.csdn.net/MooKee_cc/article/details/52947332
命令行启动
代码语言:javascript复制$ flask run --port=8080
运行过程
- 客户端向服务器发起请求
- 服务器把请求交给Flask实例
- Flask实例通过
Werkzeug
根据URL请求与视图函数之间的对应关系来进行路由分发 - 根据每个URL请求,找到具体的视图函数并进行调用
- Flask程序中路由一般是通过程序实例的装饰器实现
- Flask调用视图函数后,可以返回2种内容:
- 字符串:将视图函数的返回值作为响应内容,返回给客户端
- HTML模板内容:获得数据后,将数据传入HTML模板中,模板引擎
Jinja2
负责渲染数据,然后返回响应数据给客户端
简单应用
- 新建一个Flask项目
- 导入Flask类
# 导入Flask
from flask import Flask
- 创建实例。需要传入一个参数
name
,指向程序所在的模块
app = Flask(__name__)
- 配置路由。通过装饰器将路由映射到视图函数
@app.route('/')
def index():
return 'Hello World!'
- 完整代码
# -*- coding:utf-8 -*-
# 导入Flask
from flask import Flask
# 创建实例
app = Flask(__name__)
# 路由与视图函数对应关系
@app.route('/')
def index():
return 'Hello World!'
# 启动程序
if __name__ == '__main__':
app.run()
路由
请求方式
- 使用
methods
参数指定可接受的请求方式,可指定多种,默认只接受GET
请求
@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
实现render_template()
函数中第一个参数是模板文件名,后面的参数都是键值对,表示模板中变量对应的真实值
# -*- coding:utf-8 -*-
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html') # templates目录下的index.html
if __name__ == '__main__':
app.run()
动态渲染
- 如果需要在模板中使用某些动态的参数,则需要在视图函数中传递参数
- 视图函数中通过
render_template()
函数传参 - HTML模板文件中通过
{{}}
使用该变量
- 视图函数中通过
@app.route('/')
def index():
url = "www.naraku.cn"
return render_template('index.html', url=url)
index.html
:
<h1>欢迎来到: {{ url }}</h1>
用法
- 注释:
{# #}
{# 这是注释 #}
{# {{name}} #}
- 控制:
{% %}
{% if id>50 %}
{{id}} => 大于50
{% elif id<50 %}
{{id}} => 小于50
{% else %}
{{id}} => 等于50
{% endif %}
{% for num in nums %}
<p>当前数字为: {{num}}</p>
{% endfor %}
- 举个例子
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)
代码语言:javascript复制{# 字符串变大写 #}
<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
:全部转为大写或小写
<p>{{ 'Hello World' | lower }}</p>
<p>{{ 'Hello World' | upper }}</p>
reverse
:字符串反转
<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
- 引入
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()
函数获取消息并渲染
<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
赋值即可
- 只需要一行代码,给
from flask import Flask, render_template, request, flash
app = Flask(__name__)
app.secret_key = "naraku" # 设置密钥
....
- 如果使用Python2进行开发,可能会遇到
UnicodeDecodeError
等编码的问题,只需要在中文字符前面加个u
进行转码即可
@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")
代码语言:javascript复制{% 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
- 导入所需的表单字段
- 继承自基类
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)
- 前端渲染
<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>
- 完整代码
# -*- 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()
表单验证
- 引入验证函数,并在表单类中实现
- 必须开启
CSRF_token
,否则验证失败 - 通过
validators
传递需要调用的函数,可以为一个列表 DataRequired()
,判断字段是否非空EqualTo()
,判断当前字段与目标字段是否相等。第1个参数为目标字段,第2个参数为错误消息
- 必须开启
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()
函数一行实现表单验证
- 通过
@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>
- 完整代码
# -*- 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)
常用字段
字段对象 | 说明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码字段 |
HiddenField | 隐藏文件字段 |
DateField | 文本字段,值为 datetime.date 文本格式 |
DateTimeField | 文本字段,值为 datetime.datetime 文本格式 |
IntegerField | 文本字段,值为整数 |
DecimalField | 文本字段,值为decimal.Decimal |
FloatField | 文本字段,值为浮点数 |
BooleadnField | 复选框,True/False |
常用验证函数
验证函数 | 说明 |
---|---|
DataRequired | 确保字段中有数据 |
EqualTo | 比较两个字段的值,常用于判断两次密码是否一致 |
Length | 验证输入的字符串长度 |
NumberRange | 验证输入的数值范围 |
URL | 验证URL |
AnyOf | 验证输入值在可选列表中 |
NoneOf | 验证输入值不在可选列表中 |
插件-数据库-SQLAlchemy
SQLAlchemy
是一个关系型数据库框架,它提供了高层ORM和底层的原生数据库操作,Flask-sqlalchemy
是一个简化了的SQLAlchemy
操作的扩展。SQLAchemy
实际上是对数据库的抽象,让开发者不用直接和SQL语句打交道,而是通过Python对象来操作数据库。- 安装
Flask-sqlalchemy
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对象
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)
- 创建一个数据库,打开命令行登录数据库后输入
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
实现,继承自db.Model
- 定义表名:
__tablename__
- 定义字段:
db.Column(字段类型, 列选项)
- 指定外键:
db.ForeignKey('表名.列名')
- 通过
class Role(db.Model):
# 定义表名
__tablename__ = 'roles'
# 定义字段
id = db.Column(db.Integer, primary_key=True) # 主键
name = db.Column(db.String(16), unique=True) # 唯一
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')) # 外键
- 创建表
if __name__ == '__main__':
# db.drop_all() # 删除表
db.create_all() # 新建表
# app.run()
基本操作
- 增删改操作,由数据库会话
db.session
管理- 在准备把数据写入数据库前,要先将数据添加到会话中,然后调用
db.session.commit()
方法提交会话
- 在准备把数据写入数据库前,要先将数据添加到会话中,然后调用
- 查询操作,通过
query
对象进行操作- 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询
增删改
代码语言:javascript复制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() # 提交到数据库
查询
简单应用
- 先建表并添加数据
# -*- coding:utf-8 -*-
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()
- 这里借助
ipython
这个库,可以直接在Pycharm
下方的Terminal
终端调用进行查询。如果没有ipython
的可通过File-> setting-> Project Interpreter
进行安装 - 安装完成后在
Terminal
输入ipython
进入,并导入当前文件全部代码
> ipython
IN [1]: from demo import *
- 开始查询操作
# 查询全部用户
User.query.all()
# 查询用户总数
User.query.count()
# 查询第1个用户
User.query.first()
# 查询id为4的用户
## 因为id是主键,可通过执行器get查询
User.query.get(4)
## 通过过滤器查询
User.query.filter_by(id=4).first()
User.query.filter(User.id==4).first()
查询执行器
表模型名.query.方法()
方法 | 说明 |
---|---|
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如未查到,返回None |
first_or_404() | 返回查询的第一个结果,如未查到,返回404 |
get() | 返回指定主键对应的行,如不存在,返回None |
get_or_404() | 返回指定主键对应的行,如不存在,返回404 |
count() | 返回查询结果的数量 |
paginate() | 返回一个Paginate对象,它包含指定范围内的结果 |
查询过滤器
过滤器 | 说明 |
---|---|
filter(对象.属性==值) | 把过滤器添加到原查询上,返回一个新查询。支持比较运算符 |
filter_by(属性=值) | 把等值过滤器添加到原查询上,返回一个新查询 |
limit | 使用指定的值限定查询返回结果 |
offset() | 偏移原查询返回的结果 |
order_by() | 根据指定条件对原查询进行排序,返回一个新查询 |
group_by() | 根据指定条件对原查询进行分组,返回一个新查询 |
关系引用
有时候需要一些属性方便查询数据,但是这些属性不能出现在数据库的字段中
relationship()
:sqlalchemy
对关系之间提供的一种便利的调用方式,关联不同的表- 第1个参数:对象模型名。指需要关联的对象,可在
Role
类的实例中通过role.users
查看该实例在User
模型中的属性 backref
参数:对关系提供反向引用的声明。可在User
类的实例中通过user.role
查看该实例在Role
模型中的属性
- 第1个参数:对象模型名。指需要关联的对象,可在
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)
:输出某个实例化对象时的回显
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, primary_key=True)
name = db.Column(db.String(16), unique=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) # 外键
def __repr__(self):
return f'<User: {self.name}, {self.id}>'
@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)
常见字段
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 | 二进制文件 |
常见列选项
选项名 | 说明 |
---|---|
primary_key | 主键。若为True,即为表的主键 |
unique | 唯一。若为True,即此列不允许出现重复的值 |
default | 默认值。为此列定义默认值 |
index | 索引。若为True,为此列创建索引,提高查询效率 |
nullable | 非空。若为True,允许为空,反之不允许为空 |
依赖包
代码语言:javascript复制$ pip freeze > requirements.txt # 输出依赖包及版本到文本
$ pip install -r requirements.txt # 安装依赖包