小记 - Flask基础

2021-07-29 11:04:24 浏览数 (1)

Flask基础

  • 传值总结:https://blog.csdn.net/MooKee_cc/article/details/52947332

命令行启动

代码语言:javascript复制
$ flask run --port=8080

运行过程

  1. 客户端向服务器发起请求
  2. 服务器把请求交给Flask实例
  3. Flask实例通过Werkzeug根据URL请求与视图函数之间的对应关系来进行路由分发
  4. 根据每个URL请求,找到具体的视图函数并进行调用
    • Flask程序中路由一般是通过程序实例的装饰器实现
  5. Flask调用视图函数后,可以返回2种内容:
    • 字符串:将视图函数的返回值作为响应内容,返回给客户端
    • HTML模板内容:获得数据后,将数据传入HTML模板中,模板引擎Jinja2负责渲染数据,然后返回响应数据给客户端

简单应用

  • 新建一个Flask项目
  • 导入Flask类
代码语言:javascript复制
# 导入Flask
from flask import Flask
  • 创建实例。需要传入一个参数name,指向程序所在的模块
代码语言:javascript复制
app = Flask(__name__)
  • 配置路由。通过装饰器将路由映射到视图函数
代码语言:javascript复制
@app.route('/')
def index():
    return 'Hello World!'
  • 完整代码
代码语言:javascript复制
# -*- 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请求
代码语言:javascript复制
@app.route('/', methods=['GET','POST'])
def hello():
    return 'Hello'

参数处理

  • 有时候需要将同一类URL映射到同一个视图函数处理,例如某个分类下不同的图书返回不同信息
    • 使用<>定义路由动态参数
    • 并且将该参数传入视图函数
代码语言:javascript复制
@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
代码语言:javascript复制
@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()函数中第一个参数是模板文件名,后面的参数都是键值对,表示模板中变量对应的真实值
代码语言:javascript复制
# -*- 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模板文件中通过{{}}使用该变量
代码语言:javascript复制
@app.route('/')
def index():
    url = "www.naraku.cn"
    return render_template('index.html', url=url)
  • index.html
代码语言:javascript复制
<h1>欢迎来到: {{ url }}</h1>

用法

  • 注释:{# #}
代码语言:javascript复制
{# 这是注释 #}
{# {{name}} #}
  • 控制:{% %}
代码语言:javascript复制
{% if id>50 %}
    {{id}} => 大于50
{% elif id<50 %}
    {{id}} => 小于50
{% else %}
    {{id}} => 等于50
{% endif %}


{% for num in nums %}
    <p>当前数字为: {{num}}</p>
{% endfor %}
  • 举个例子
代码语言:javascript复制
def index():
    id = 100
    nums = [1, 2, 3, 4, 5]
    return render_template('index.html', id=id, nums=nums)

index.html

代码语言:javascript复制
{% 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中某些方法的,那么就用到了过滤器

使用方式:

  • 过滤器的使用方式:变量名 | 过滤器
代码语言:javascript复制
{{ name | filter(*args) }}
  • 如果没有任何参数传给过滤器,可以省略括号
代码语言:javascript复制
{{ name | filter }}
  • 举个例子
代码语言:javascript复制
@app.route('/')
def index():
    name = "naraku"
    return render_template('index.html', name=name)
代码语言:javascript复制
{# 字符串变大写 #}
<p>{{ name | upper }}</p>

链式调用

Jinja2中,过滤器支持链式调用,从左到右按顺序执行

代码语言:javascript复制
<p>{{ 'Hello World' | upper | reverse }}</p>

常用过滤器

  • format:格式化输出
代码语言:javascript复制
<p>{{ '%s' | format(name) }}</p>
  • safe:禁用转义
代码语言:javascript复制
<p>{{ '<em>hello</em>' | safe }}</p>
  • capitalize:首字母大写,其余小写
代码语言:javascript复制
<p>{{ 'hello' | capitalize }}</p>
  • upper/lower:全部转为大写或小写
代码语言:javascript复制
<p>{{ 'Hello World' | lower }}</p>

<p>{{ 'Hello World' | upper }}</p>
  • reverse:字符串反转
代码语言:javascript复制
<p>{{ 'Hello World' | reverse }}</p>
  • truncate:字符串截断
代码语言:javascript复制
<p>{{ 'hello world' | truncate(3) }}</p>
  • striptags:渲染前把所有HTML标签删除
代码语言:javascript复制
<p>{{ '<em>hello</em>' | striptags }}</p>

Web表单

Web表单是Web程序的基本功能,它是HTML页面中负责数据采集的部件。表单中有三部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。

简单示例

视图函数

  • 路由需要有GETPOST请求,需要判断请求方式
    • 路由中添加参数methods,以列表的方式传入请求方式GETPOST
    • 引入request对象,获取请求方式及参数
代码语言:javascript复制
@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")
  • 模板文件
代码语言:javascript复制
<!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
代码语言:javascript复制
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()函数获取消息并渲染
代码语言:javascript复制
<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赋值即可
代码语言:javascript复制
from flask import Flask, render_template, request, flash

app = Flask(__name__)
app.secret_key = "naraku"   # 设置密钥

....
  • 如果使用Python2进行开发,可能会遇到UnicodeDecodeError等编码的问题,只需要在中文字符前面加个u进行转码即可
代码语言:javascript复制
@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=["分类名"]过滤调用
代码语言:javascript复制
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防护会根据设置的密钥生成加密令牌
  • 需要先安装此插件
代码语言:javascript复制
pip install Flask-WTF 

基本示例

  • 先自定义一个表单类
    • 继承自基类FlaskForm
    • 导入所需的表单字段
代码语言:javascript复制
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("提交")
  • 传递到模板
代码语言:javascript复制
@app.route("/reg", methods=['GET', 'POST'])
def reg():
    reg_form = RegForm()
    return render_template("index.html", reg_form=reg_form)
  • 前端渲染
代码语言:javascript复制
<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>
  • 完整代码
代码语言:javascript复制
# -*- 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个参数为错误消息
代码语言:javascript复制
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()函数一行实现表单验证
代码语言:javascript复制
@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() 函数开启
代码语言:javascript复制
<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>
  • 完整代码
代码语言:javascript复制
# -*- 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
代码语言:javascript复制
pip install flask-sqlalchemy
  • 如果需要操作Mysql,还需要安装mysqldb
代码语言:javascript复制
pip install flask-mysqldb

管理数据库

  • Flask-SQLAlchemy中,数据库使用URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中
    • 数据库类型://数据库账号:密码@地址:端口/数据库名
代码语言:javascript复制
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:root@127.0.0.1:3306/flask'
  • 其它设置
代码语言:javascript复制
# 动态追踪修改设置,如未设置只会提示警告,不建议开启
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

创建数据库对象

  • 引入相关库,配置app对象的数据库信息,创建数据库对象,并传入当前app对象
代码语言:javascript复制
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)
  • 创建一个数据库,打开命令行登录数据库后输入
代码语言:javascript复制
 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('表名.列名')
代码语言:javascript复制
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'))  # 外键
  • 创建表
代码语言:javascript复制
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()
  • 其它语句
代码语言:javascript复制
db.session.add(role)   # 添加到数据库的session中
db.session.add_all([user1, user2])  # 以列表形式添加多个
db.session.rollback()    # 回滚操作
db.session.delete(user)  # 删除数据
db.session.commit()      # 提交到数据库
查询
简单应用
  • 先建表并添加数据
代码语言:javascript复制
# -*- 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进入,并导入当前文件全部代码
代码语言:javascript复制
> ipython
IN [1]: from demo import *
  • 开始查询操作
代码语言:javascript复制
# 查询全部用户
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模型中的属性
代码语言:javascript复制
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):输出某个实例化对象时的回显
代码语言:javascript复制
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  # 安装依赖包

0 人点赞