Flask基础

命令行启动

$ flask run --port=8080

运行过程

  1. 客户端向服务器发起请求
  2. 服务器把请求交给Flask实例
  3. Flask实例通过Werkzeug根据URL请求与视图函数之间的对应关系来进行路由分发
  4. 根据每个URL请求,找到具体的视图函数并进行调用

    • Flask程序中路由一般是通过程序实例的装饰器实现
  5. 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/abcstr类型的路由时会返回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)
{# 字符串变大写 #}
<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页面数据采集,通过表单将用户输入的数据提交给服务器。

简单示例

视图函数

  • 路由需要有GETPOST请求,需要判断请求方式

    • 路由中添加参数methods,以列表的方式传入请求方式GETPOST
    • 引入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

flask-1

  • 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")
{% 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_iduser_namerole_id(外键)
11号管理1
22号管理1
3用户A2
  • 实现数据模型

    • 通过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()

flask-2

基本操作

  • 增删改操作,由数据库会话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()

flask-3

  • 其它语句
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()

flask-4

  • 这里借助ipython这个库,可以直接在Pycharm下方的Terminal终端调用进行查询。如果没有ipython的可通过File-> setting-> Project Interpreter进行安装
  • 安装完成后在Terminal输入ipython进入,并导入当前文件全部代码
> ipython
IN [1]: from demo import *

flask-5

  • 开始查询操作
# 查询全部用户
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()


flask-6

查询执行器

表模型名.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模型中的属性
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数据类型说明
Integetint普通整数,一般是32位
SmallIntegetint取值范围小的整数,一般是16位
BigIntegetint/long不限制精度的
Floatfloat浮点数
Numericdecimal.Decimal普通整数,一般是32位
Stringstr变长字符串
Textstr变长字符串,对较长或不限长度的字符串做了优化
Unicodeunicode变长Unicode字符串
UnicodeTextunicode变长Unicode字符串,对较长或不限长度的字符串做了优化
Booleanbool布尔值
Datedatetime.date时间
Timedatetime.datetime日期和时间
LargeBinarystr二进制文件

常见列选项

选项名说明
primary_key主键。若为True,即为表的主键
unique唯一。若为True,即此列不允许出现重复的值
default默认值。为此列定义默认值
index索引。若为True,为此列创建索引,提高查询效率
nullable非空。若为True,允许为空,反之不允许为空

依赖包

$ pip freeze > requirements.txt    # 输出依赖包及版本到文本
$ pip install -r requirements.txt  # 安装依赖包
如果觉得我的文章对你有帮助,请我吃颗糖吧~