一、Jinja2模板引擎
Flask内置的模板语言,它的设计思想来源于 Django 的模板引擎,并扩展了其语法和一系列强大的功能。
渲染模版函数
- Flask提供的 render_template 函数封装了该模板引擎
- render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的真实值。
1.模板基本使用
(1)在flask应用对象创建的时候,设置或者保留template_folder参数,创建模板目录
app = Flask(__name__,template_folder='templates')
(2)在项目下创建 templates
文件夹,用于存放所有的模板文件,并在目录下创建一个模板html文件 index1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{title}}</h1>
<p>num={{num}}</p>
</body>
</html>
(3)在视图函数设置渲染模板并设置模板数据
from flask import Flask,render_template
app = Flask(__name__, template_folder='templates')
@app.route('/')
def index():
data = {}
data['title'] = '我的第一个flask网页'
data['num'] = 100
return render_template('index1.html', **data)
if __name__ == '__main__':
app.run(debug=True)
输出变量
{{}} 来表示变量名,这种 {{}} 语法叫做 变量代码块
使用 {# #} 进行注释,注释的内容不会在html中被渲染出来
{# {{ name }} #}
2.模板语句
主程序:
from flask import Flask, render_template
app = Flask(__name__, template_folder='templates')
@app.route('/')
def index():
data = {}
data['info'] = {
'name': 'xiaoming',
'age': 19,
'sex': True,
'class': '1009'
}
data['student_list'] = ['xiaoming', 'xiaobai', 'xiaohei', 'xiaoan']
data['goods_list'] = [
{'id': 10, 'name': 'Python7天入门到放弃', 'price': 99.9, 'num': 100},
{'id': 11, 'name': 'Python3天入门到放弃', 'price': 99.9, 'num': 100},
{'id': 12, 'name': 'Python5天入门到放弃', 'price': 99.9, 'num': 100},
{'id': 13, 'name': 'Go7天入门到放弃', 'price': 99.9, 'num': 100},
{'id': 14, 'name': 'Go5天入门到放弃', 'price': 99.9, 'num': 100},
{'id': 15, 'name': 'Linux7天入门到放弃', 'price': 99.9, 'num': 100},
]
return render_template('index2.html', **data)
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>访问字典数据中的成员</p>
<p>{{ info['name'] }}</p>
<p>{{ info.name }}</p>
<p>访问列表数中的成员,点语法不支持负数下标</p>
<p>{{ student_list.0 }}</p>
<p>{{ student_list.2 }}</p>
<p>{{ student_list[-1] }}</p>
<p>{{ student_list[2] }}</p>
<p>if判断</p>
{% if info.age < 18 %}
<p>小明请出去</p>
{% endif %}
{% if info.age > 10 %}
<p>小明同学</p>
{% else %}
<p>小明小朋友</p>
{% endif %}
{% if info.age < 10 %}
<p>小明小朋友</p>
{% elif info.age < 18 %}
<p>小明同学</p>
{% else %}
<p>大明同学</p>
{% endif %}
<p>for循环</p>
<ul>
{% for student in student_list %}
{% if loop.last %}
<li style="background-color:#000;color: brown;">{{ student }}</li>
{% else %}
<li>{{ student }}</li>
{% endif %}
{% endfor %}
</ul>
<table border="1" align="center" width="680px">
<tr>
<td>序号</td>
<td>ID</td>
<td>名称</td>
<td>价格</td>
<td>库存</td>
</tr>
{# flask的注释 #}
{# loop是jinja2模板引擎提供给开发者获取循环中的信息对象 #}
{# loop.index 显示本次循环的次数,从1开始 #}
{# loop.index0 显示本次循环的次数,从0开始 #}
{# loop.first 显示本次是否属于循环的第一次,是则为真 #}
{% for goods in goods_list %}
{% if loop.index % 2 %}
<tr bgcolor="#6495ed">{% else %}</tr>
{% endif %}
<td>{{ loop.index0 }}</td>
<td>{{ goods.id }}</td>
<td>{{ goods.name }}</td>
<td>{{ goods.price }}</td>
<td>{{ goods.num }}</td>
{% endfor %}
</table>
</body>
</html>
如图:
以上包括流程控制
主要包含两个:
- if/elif /else / endif
- for / endfor
在一个 for 循环块中你可以访问这些特殊的变量:
变量 | 描述 |
---|---|
loop.index | 当前循环迭代的次数(从 1 开始) |
loop.index0 | 当前循环迭代的次数(从 0 开始) |
loop.revindex | 到循环结束需要迭代的次数(从 1 开始) |
loop.revindex0 | 到循环结束需要迭代的次数(从 0 开始) |
loop.first | 如果是第一次迭代,为 True 。 |
loop.last | 如果是最后一次迭代,为 True 。 |
loop.length | 序列中的项目数。 |
loop.cycle | 在一串序列间期取值的辅助函数。 |
3.模板中特有的变量和函数
config、request、session、g变量、url_for()
主程序:
app.config['SECRET_KEY'] = '123sd'
@app.route('/')
def index():
data = {}
session['name'] = 'xiaohuihui'
return render_template('index3.html', **data)
if __name__ == '__main__':
app.run(debug=True)
模板 templates/index3.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 获取上下文对象 #}
<p>{{ request.url }}</p>
<p>{{ request.method }}</p>
<p>{{ session }}</p>
<p>{{ session.name}}</p>
<p>{{ config.DEBUG }}</p>
<p>{{ url_for('index') }}</p>
</body>
</html>
pycharm中设置当前项目的模板语言:
files/settings/languages & frameworks/python template languages。
设置下拉框为jinja2,保存
二、过滤器
过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,而在模板中是不能直接调用 Python 中的某些方法,那么这就用到了过滤器。
在 jinja2 中,过滤器是可以支持链式调用的,示例如下
{{ "hello world" | reverse | upper }}
1.常见的内建过滤器
(1)字符串操作
safe:禁用转义
capitalize:把变量值的首字母转成大写,其余字母转小写
lower:把值转成小写
upper:把值转成大写
title:把值中的每个单词的首字母都转成大写
reverse:字符串反转
format:格式化输出
striptags:渲染之前把值中所有的HTML标签都删掉
如果内容中,存在大小于号的情况,则不要使用这个过滤器,容易误删内容。
truncate: 字符串截断
(2)列表操作
first:取第一个元素
last:取最后一个元素
length:获取列表长度
sum:列表求和
sort:列表排序
(3)语句块过滤
{% filter upper %}
#一大堆文字#
{% endfilter %}
主函数:
from flask import Flask, render_template
app = Flask(__name__, # 当前flask应用运行的模块
static_folder='static', # 当前flask应用保存静态资源[css/js/img/音视频]
static_url_path='/lib', # 当前flask应用提供给外界访问的路径前缀,必须以/开头
template_folder='templates'
)
app.config['SECRET_KEY'] = '12sdf'
@app.route('/')
def index():
data = {}
data['message'] = 'hello,python,after 7 day,byebye'
data['image'] = "<img src='/lib/images/1.jpg'>"
return render_template('index4.html', **data)
if __name__ == '__main__':
app.run(debug=True)
index4.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
img{
width: 100px;
}
</style>
</head>
<p>{{ message | upper }}</p>
<p>{{ image | safe }}</p>
<p>{{ message | reverse | upper }}</p>
<p>{{ '<em>hello</em>' | striptags }}</p>
<p>{{ '如果x<y,z>x,那么x和z之间是否相等?' | striptags }}</p>
<p>{{ '床前明月光,疑是地上霜。' | truncate(5,False,'...',0) }}</p>
<p>{{ [1,1,2,3,4,5,1,2,2,3,4] | unique | list }}</p>
<body>
</body>
</html>
![](https://i-blog.csdnimg.cn/blog_migrate/1666039913976c34b4646931adaabde7.png)
2.自定义过滤器
过滤器的本质是函数。当模板内置的过滤器不能满足需求,可以自定义过滤器。自定义过滤器有两种实现方式:
- 一种是通过Flask应用对象的 add_template_filter 方法
- 通过装饰器来实现自定义过滤器
重要:自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器。
案例:给手机号码进行部分屏蔽
主函数:
from flask import Flask, render_template
app = Flask(__name__,
static_folder='static',
static_url_path='/lib',
template_folder='templates'
)
app.config['SECRET_KEY'] = '1ds2d'
# 自定义过滤器函数
def do_mobile(content):
return content[:3]+'*****'+content[-3:]
app.add_template_filter(do_mobile, 'mobile')
@app.route('/')
def index():
data = {}
data['mobile_list'] = [
'13564985647',
'13564985648',
'13564985649',
]
return render_template('index5.html', **data)
if __name__ == '__main__':
app.run(debug=True)
index5.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for mobile in mobile_list %}
<p>{{ mobile | mobile }}</p>
{% endfor %}
</body>
</html>
三、模板继承
在模板中,可能会遇到以下情况:
- 多个模板具有完全相同的顶部和底部内容
- 多个模板中具有相同的模板代码内容,但是内容中部分值不一样
- 多个模板中具有完全相同的 html 代码块内容
像遇到这种情况,可以使用 JinJa2 模板中的 继承 来进行实现
模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。
-
标签定义的内容
{% block top %} {% endblock %}
-
相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。
-
子模板使用 extends 指令声明这个模板继承自哪个模板
-
父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用
super()
父模板代码:base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}父级模板的内容{% endblock %}</title>
{% block hander %}{% endblock hander %}
</head>
<body>
{% block content %}
<p>父级模板的content</p>
{% endblock content %}
</body>
</html>
子模板代码:index6.html
{% extends 'base.html' %}
{% block title %}来自子模板的标题{% endblock title %}
{% block hander %}
<script>
alert(1)
</script>
{% endblock hander %}
{% block content %}
{{ super() }}
<p>子模板的内容</p>
{{ super() }}
{% endblock %}
from flask import Flask, render_template
app = Flask(__name__, template_folder='templates')
@app.route('/')
def index():
data = {}
return render_template('index6.html', **data)
if __name__ == '__main__':
app.run(debug=True)
模板继承使用时注意点:
1. 不支持多继承
2. 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
3. 不能在一个模板文件中定义多个相同名字的block标签。
4. 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。
四、解决csrf攻击
pip install flask_wtf
1.设置应用程序的 secret_key,用于加密生成的 csrf_token 的值
# 1. session加密的时候已经配置过了.如果没有在配置项中设置,则如下:
app.secret_key = "#此处可以写随机字符串#"
# 2. 也可以写在配置类中。
class Config(object):
DEBUG = True
SECRET_KEY = "dsad32"
"""加载配置"""
app.config.from_object(Config)
2.导入 flask_wtf.csrf 中的 CSRFProtect 类,进行初始化,并在初始化的时候关联 app
from flask.ext.wtf import CSRFProtect
CSRFProtect(app)
在表单中使用 CSRF 令牌:
<form method="post" action="/">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
视图代码:
rom flask import Flask, render_template, request
from flask_wtf import CSRFProtect
app = Flask(__name__, template_folder='templates')
csrf = CSRFProtect(app)
app.config['SECRET_KEY'] = '254dgf'
@app.route('/')
def index():
data = {}
return render_template('index7.html', **data)
@app.route('/login', methods=['POST'])
def login():
print(request.form)
return 'ok'
if __name__ == '__main__':
app.run(debug=True)
模板代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form action="{{ url_for('login') }}" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
帐号:<input type="text" name="username" value=""><br><br>
密码:<input type="password" name="password" value=""><br><br>
<input type="submit" value="登录">
</form>
</body>
</html>
五、数据库操作
1.ORM
ORM 全拼Object-Relation Mapping
,中文意为 对象-关系映射。主要实现模型对象到关系数据库数据的映射
优点 :
- 只需要面向对象编程, 不需要面向数据库编写代码.
- 对数据库的操作都转化成对类属性和方法的操作.
- 不用编写各种数据库的
sql语句
.
- 实现了数据模型与数据库的解耦, 屏蔽了不同数据库操作上的差异.
- 不再需要关注当前项目使用的是哪种数据库。
- 通过简单的配置就可以轻松更换数据库, 而不需要修改代码.
缺点 :
- 相比较直接使用SQL语句操作数据库,有性能损失.
- 根据对象的操作转换成SQL语句,根据查询的结果转化成对象, 在映射过程中有性能损失.
2.Flask-SQLAlchemy
flask默认提供模型操作,但是并没有提供ORM,所以一般开发的时候我们会采用flask-SQLAlchemy模块来实现ORM操作。
SQLAlchemy是一个关系型数据库框架,它提供了高层的 ORM 和底层的原生数据库的操作。flask-sqlalchemy 是一个简化了 SQLAlchemy 操作的flask扩展。
SQLAlchemy: https://www.sqlalchemy.org/
中文文档: https://www.osgeo.cn/sqlalchemy/index.html
安装 flask-sqlalchemy【清华源】
pip install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
如果连接的是 mysql 数据库,需要安装 mysqldb 驱动
pip install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
安装flask-mysqldb时,注意
安装 flask-mysqldb的时候,python底层依赖于一个底层的模块 mysql-client模块
如果没有这个模块,则会报错如下:
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-21hysnd4/mysqlclient/
解决方案:
sudo apt-get install libmysqlclient-dev python3-dev
运行上面的安装命令如果再次报错如下:
dpkg 被中断,您必须手工运行 ‘sudo dpkg --configure -a’ 解决此问题。
则根据提示执行命令以下命令,再次安装mysqlclient
sudo dpkg --configure -a
apt-get install libmysqlclient-dev python3-dev
解决了mysqlclient问题以后,重新安装 flask-mysqldb即可。
pip install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
(1)数据库连接设置
class Config():
DEBUG = True
# 数据库连接配置
# SQLALCHEMY_DATABASE_URI = "mysql://账号:密码@IP/数据库名?编码"
SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
配置完成需要去 MySQL 中创建项目所使用的数据库
$ mysql -uroot -p1
mysql > create database students charset=utf8mb4;
(2)常用的SQLAlchemy字段类型
模型字段类型名 | python中数据类型 | 说明 |
---|---|---|
Integer | int | 普通整数,一般是32位 |
SmallInteger | int | 取值范围小的整数,一般是16位 |
BigInteger | 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.time | 时间 |
DateTime | datetime.datetime | 日期和时间 |
LargeBinary | str | 二进制文件内容 |
(3)常用的SQLAlchemy列约束选项
选项名 | 说明 |
---|---|
primary_key | 如果为True,代表表的主键 |
unique | 如果为True,代表这列不允许出现重复的值 |
index | 如果为True,为这列创建索引,提高查询效率 |
nullable | 如果为True,允许有空值,如果为False,不允许有空值 |
default | 为这列定义默认值 |
3.数据库基本操作
- 在Flask-SQLAlchemy中,添加、修改、删除操作,均由数据库会话管理。
- 会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 db.commit() 方法提交会话。
- 在 Flask-SQLAlchemy 中,查询操作是通过 query 对象操作数据。
- 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。
定义模型类
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
class Config():
DEBUG = True
# 数据库连接配置
# SQLALCHEMY_DATABASE_URI = "mysql://账号:密码@IP/数据库名?编码"
SQLALCHEMY_DATABASE_URI = 'mysql://root:1@127.0.0.1:3306/students?charset=utf8mb4'
# # 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
db = SQLAlchemy()
db.init_app(app)
"""创建模型类"""
class Student(db.Model):
__tablename__ = 'tb_student'
id = db.Column(db.Integer, primary_key=True, comment='主键ID')
name = db.Column(db.String(250), comment='姓名')
age = db.Column(db.Integer, comment='年龄')
sex = db.Column(db.Boolean, default=False, comment='性别')
money = db.Column(db.DECIMAL(8, 2), nullable=True, comment='钱包')
def __repr__(self):
return self.name
class Teacher(db.Model):
__tablename__ = 'tb_teacher'
id = db.Column(db.Integer, primary_key=True, comment='主键ID')
name = db.Column(db.String(250), comment='姓名')
sex = db.Column(db.Boolean, default=False, comment='性别')
option = db.Column(db.Enum('讲师', '助教', '班主任'), default='讲师', comment='教职')
def __repr__(self):
return self.name
class Course(db.Model):
__tablename__ = 'tb_course'
id = db.Column(db.Integer, primary_key=True, comment='主键ID')
name = db.Column(db.String(250), unique=True, comment='课程名称')
price = db.Column(db.Numeric(6, 2))
def __repr__(self):
return self.name
@app.route('/')
def index():
return 'ok'
if __name__ == '__main__':
with app.app_context():
db.create_all() # 根据模型创建所有的数据表
db.drop_all() # 删除模型对应的所有数据表
app.run()
六、数据表操作
增删改查
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
class Config():
DEBUG = True
# 数据库连接配置
# SQLALCHEMY_DATABASE_URI = "mysql://账号:密码@IP/数据库名?编码"
SQLALCHEMY_DATABASE_URI = 'mysql://root:1@127.0.0.1:3306/students?charset=utf8mb4'
# # 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
db = SQLAlchemy()
db.init_app(app)
"""创建模型类"""
class Student(db.Model):
__tablename__ = 'tb_student'
id = db.Column(db.Integer, primary_key=True, comment='主键ID')
name = db.Column(db.String(250), comment='姓名')
age = db.Column(db.Integer, comment='年龄')
sex = db.Column(db.Boolean, default=False, comment='性别')
money = db.Column(db.DECIMAL(8, 2), nullable=True, comment='钱包')
def __repr__(self):
return self.name
class Teacher(db.Model):
__tablename__ = 'tb_teacher'
id = db.Column(db.Integer, primary_key=True, comment='主键ID')
name = db.Column(db.String(250), comment='姓名')
sex = db.Column(db.Boolean, default=False, comment='性别')
option = db.Column(db.Enum('讲师', '助教', '班主任'), default='讲师', comment='教职')
def __repr__(self):
return self.name
class Course(db.Model):
__tablename__ = 'tb_course'
id = db.Column(db.Integer, primary_key=True, comment='主键ID')
name = db.Column(db.String(250), unique=True, comment='课程名称')
price = db.Column(db.Numeric(6, 2))
def __repr__(self):
return self.name
@app.route('/')
def index():
"""数据库基本操作"""
"""添加数据"""
# 添加一条数据
# student = Student(name='xiaohong', age=16, money=100, sex=True)
# db.session.add(student)
# db.session.commit()
# 批量添加多条数据
data_list = [
Student(name='xiaohui1号', age=16, money=1000, sex=True),
Student(name='xiaohui2号', age=16, money=1000, sex=True),
Student(name='xiaohui3号', age=16, money=1000, sex=True),
Student(name='xiaohui4号', age=16, money=1000, sex=True),
Student(name='xiaohui5号', age=16, money=1000, sex=True),
Student(name='xiaohui6号', age=16, money=1000, sex=True),
]
db.session.add_all(data_list)
db.session.commit()
"""查询数据"""
# 根据主键ID查询一条数据,如果ID不存在,则返回None不会报错!
# student = Student.query.get(100)
# if student is None:
# print('当前学生不存在!')
# else:
# print(student)
# print(student.name, student.age) # 获取属性
# 根据查询条件获取一条数据
# 模型.query.filter(模型.字段==条件值).first()
# student = Student.query.filter(Student.id==1).first()
# print(student)
# print(student.name, student.money)
# 根据查询条件获取多条数据
# 模型.query.filter(模型.字段==条件值).all()
# student_list = Student.query.filter(Student.id < 5).all()
# print(student_list)
# """
# [xiaohong, xiaohui1号, xiaohui2号, xiaohui3号]
# """
# for student in student_list:
# print(student.name, student.money)
"""更新数据"""
# 先查询后修改
# student = Student.query.filter(Student.name=='xiaohong').first()
# student.money += 1000
# db.session.commit()
# 直接根据条件修改
# Student.query.filter(Student.name=='xiaohong', Student.money==2100).update({Student.money:3000}) # 乐观锁
# 实现类似django的F函数效果,字段值累加
# Student.query.filter(Student.name=='xiaohong').update({Student.money:Student.money+500})
# db.session.commit()
"""删除数据"""
# 先查询后删除
# student = Student.query.filter(Student.name=='xiaohui6号').first()
# db.session.delete(student)
# db.session.commit()
# 直接根据条件进行删除操作
Student.query.filter(Student.name=='xiaohui5号').delete()
db.session.commit()
return 'ok'
if __name__ == '__main__':
app.run()
1.数据基本查询
常用的SQLAlchemy查询过滤器
过滤器 | 说明 |
---|---|
filter() | 把过滤器添加到原查询上,返回一个新查询 |
filter_by() | 把等值过滤器添加到原查询上,返回一个新查询 |
limit() | 使用指定的值限定原查询返回的结果 |
offset() | 偏移原查询返回的结果,返回一个新查询 |
order_by() | 根据指定条件对原查询结果进行排序,返回一个新查询 |
group_by() | 根据指定条件对原查询结果进行分组,返回一个新查询 |
常用的SQLAlchemy查询结果的方法
方法 | 说明 |
---|---|
all() | 以列表形式返回查询的所有结果 |
first() | 返回查询的第一个结果,如果未查到,返回None |
first_or_404() | 返回查询的第一个结果,如果未查到,返回404 |
get() | 返回指定主键对应的行,如不存在,返回None |
get_or_404() | 返回指定主键对应的行,如不存在,返回404 |
count() | 返回查询结果的数量 |
paginate() | 返回一个Paginate分页器对象,它包含指定范围内的结果 |
having | 返回结果中符合条件的数据,必须跟在group by后面,其他地方无法使用。 |