Flask中数据库关联与分页与cache缓存(十二)
1 一对多(One To Many)
表示一对多的关系时,在子表类 Post 中需要通过 foreign key (外键)引用父表类 User
在Post类中指定ForeignKey:
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.String(45), primary_key=True)
title = db.Column(db.String(255))
text = db.Column(db.Text())
publish_date = db.Column(db.DateTime)
# 设置外键ForeignKey
user_id = db.Column(db.String(45),db.ForeignKey('users.id'))
user_id 字段是 posts 表的外键,代表了外键约束。强制规定了字段 user_id 的值必须同时存在于User.id 列中。用来保证每一篇post都能对应找到一个user,而且一个user能够对应多篇 posts
在User父类指定
class User(db.Model):
# 设置表名为users
__tablename__ = 'users'
id = db.Column(db.String(45), primary_key=True)
username = db.Column(db.String(255))
password = db.Column(db.String(255))
# 设置连接posts的并反向查询users
posts = db.relationship('Post',backref='users',lazy='dynamic')
#一对多
#Post设置外键的表,属于多
user_id = db.Column(db.String(45), db.ForeignKey('users.id'))
#User设置关联的表,属于1
posts = db.relationship('Post',backref='users',lazy='dynamic')
注意:
db.relationsformat(self.username): 会在 SQLAlchemy 中创建一个虚拟的列,该列会与 Post.user_id (db.ForeignKey) 建立联系
backref:用于指定表之间的双向关系,如果在一对多的关系中建立双向的关系,这样的话在对方看来这就是一个多对一的关系,反向查询的表名
lazy:指定 SQLAlchemy 加载关联对象的方式。
lazy=subquery: 会在加载 Post 对象后,将与 Post 相关联的对象全部加载
lazy=dynamic: 只有被使用时,对象才会被加载,并且返回式会进行过滤
2 多对多(Many To Many)
class Posts(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer,primary_key=True)
content = db.Column(db.Text)
pid = db.Column(db.Integer,default=0)
path = db.Column(db.String(255),default='0,')
timestamp = db.Column(db.DateTime,default=datetime.utcnow)
#一对多posts为多,设置外键 Foreignkey
uid = db.Column(db.Integer,db.ForeignKey('user.id'))
class User(UserMixin,db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(12),index=True)
password_hash = db.Column(db.String(128))
sex = db.Column(db.Boolean,default=True)
age = db.Column(db.Integer)
email = db.Column(db.String(40))
icon = db.Column(db.String(70),default='default.jpg')
#当期账户激活状态
confirm = db.Column(db.Boolean,default=False)
#参数1模型名称 参数2反向引用的字段名 参数3 加载方式 提供对象
#post与user为一对多,一设置反向查询表名user
posts = db.relationship('posts',backref='user',lazy='dynamic')
#post与collect是多对多关系
favorite = db.relationship('Posts',secondary='collections',backref=db.backref('users',lazy='dynamic'),lazy='dynamic')
#中间表collections,多对多
collections = db.Table('collections',
db.Column('user_id',db.Integer,db.ForeignKey('user.id')),
db.Column('posts_id',db.Integer,db.ForeignKey('posts.id'))
)
关于中间表
也可以写成类的形式创建
class Collections(db.Model):
__tablename__ = 'collectionss'
user_id = db.Column('user_id', db.Integer, db.ForeignKey('user.id'))
posts_id = db.Column('posts_id', db.Integer, db.ForeignKey('posts.id'))
注意:
- many to many 的关系仍然是由
db.relationship()
来定义 - seconddary(次级):会告知 SQLAlchemy 该 many to many 的关联保存在 posts_tags 表中
- backref:声明表之间的关系是双向,帮助手册
help(db.backref)
。需要注意的是:在 one to many 中的 backref 是一个普通的对象,而在 many to many 中的 backref 是一个 List 对象。
3 数据迁移
from flask_migrate import Migrate
migrate = Migrate(main.app, models.db) #绑定app与db
manager = Manager(main.app)
manager.add_command("db", MigrateCommand) #给数据库迁移重命名db
python3 manage.py db init #初始化 DB Migrate
python3 manage.py db migrate #开始迁移生成migrations 目录,保存所有的更改记录文件
python3 manage.py db upgrade #将需要修改的数据库结构的更新内容,手动的写入到记录文件中,然后执行 upgrade 指令就能够实现数据库的更新
python manage.py db history # 获取 History ID
python manage.py db downgrade <history_id> # 回滚到某个 history
4 paginate分页类
(1) paginate 分页类
返回 pagination分页对象
参数:
page 必须参数 代表当前的页码
per_page 每页显示数据的条数 默认为20条
error_out 当分页查询出现异常的时候 是否抛出错误 默认抛出 改为Flase
(2) pagination分页对象 属性
items 当前分页的所有数据
page 当期页码
pages 总页码数
total 总记录数
per_page 每页显示数据的条数
prev_num 返回上一页的页码
next_num 返回下一页的页码
has_prev 是否存在上一页
has_next 是否存在下一页
(3) pagination分页对象 方法
prev 上一页的分页对象
next 下一页的分页对象
iter_pages 是一个迭代器 返回分页栏上的页码数 如果显示不下 返回None
5 flask-cache 缓存
安装
pip3 install flask-cache
导入使用
#自带simple缓存
from flask_cache import Cache
cache = Cache(app,config={'CACHE_TYPE': 'simple'}) #实例化cache
或者利用工厂函数
cache = Cache(config={'CACHE_TYPE': 'simple'})
def create_app(app): #工厂函数
cache.init_app(app)
#注: simple代表简单的缓存,容易出现问题,一般可以采用redis代替
cache = Cache(app, config={'CACHE_TYPE': 'redis', # Use Redis
'CACHE_REDIS_HOST': 'abc.com', # Host, default 'localhost'
'CACHE_REDIS_PORT': 6379, # Port, default 6379
'CACHE_REDIS_PASSWORD': '111', # Password
'CACHE_REDIS_DB': 2} # DB, default 0
缓存无参数的普通函数 : @ cache.cached(timeout,key_prefix)
@cache.cached(timeout=100,key_prefix='index')
#NOTE 1: 装饰器 @ cache.cached() 的形参数 key_prefix 是必须的, 并且传入的值是唯一的, 这样 Flask-Cache 才能够正确的返回该函数缓存的值.
#NOTE 2: 该函数被缓存的时间设定为100s, 这是因为该函数返回的值不被经常改变, 而且就算是被改变了也不会对整体页面的显示有大的影响.
缓存带参数的普通函数 : @cache.memoize(timeout)
不带参数的装饰器不考虑参数问题,就算函数接受不同的实参还是返回相同的结果,这明显的不科学的.因此采用记忆型的 @cache.memoize(),但是使用与纯函数调用
@cache.memoize(timeout=100)
#NOTE 1: 装饰器 @cache.memoize() 不仅仅会缓存运行的结果, 还缓存调用时的参数, 所以在函数接受到相同的参数时, 就会将缓存中该参数对应的结果返回.
#NOTE 2: @cache.momoize() 非常不适用于返回结果依赖全局变量或依赖数据库查询的函数, 因为在这很容易导致数据竞态, 即输入了相同的参数, 可能会返回不同的结果. 最适合被缓存的函数是纯函数(在传入的参数相同的情况下会输出相同的结果)
缓存无动态参数的视图函数
@blog_blueprint.route('/<int:page>')
@cache.cached(timeout=60)
#NOTE 1: 这里仍然是使用装饰器 @cache.cached(), 但却不必需要指定 key_prefix 形参.
#NOTE 2: timeout 表示该视图函数返回的结果将会被缓存的时长.
缓存带动态参数的视图函数
@blog_blueprint.route('/post/<string:post_id>', methods=('GET', 'POST'))
@cache.cached(timeout=60, key_prefix=make_cache_key)
#NOTE 1: 这里我们仍然使用了 key_prefix 参数来进行定位, 而且该形参除了可以接受 String 类型对象之后, 也可以接收一个函数.
#NOTE 2: 函数 make_cache_key() 会动态的生成一个唯一的缓存键, 用于确定这一次请求的 URL 是否存在缓存, 如果存在则返回, 如果不存在则新建. 所以在该函数中我们使用了请求 path + hash 字符串结合而成的唯一字符串作为缓存键.
删除缓存
(1) 给settings.py 设置参数
CACHE_DEFAULT_TIMEOUT
(2) 给装饰器 添加 timeout参数
@cache.cached(timeout=100)
(3) 清除所有的缓存
cache.clear()
(4) 清除cached的缓存
@cache.cached(timeout=100,key_prefix='index') #当前缓存的前缀
cache.delete('index')
(5) 清除 memoize的缓存
cache.delete_memoized(视图函数的名称)
Flask中数据库关联与分页与cache缓存(十二)的更多相关文章
- flask中注册验证码和分页
注册验证码.核心思路,替换注册页面的img标签的src属性. 1.准备好文件夹:captcha2.导包 from utils.captcha.captcha import captcha3.验证码生成 ...
- Ex3_28 在2SAT问题中,给定一个字句的集合..._第十二次作业
参考答案 ----------------------------------------------------------------------------------------------- ...
- iOS中数据库应用基础
iOS 数据库入门 一.数据库简介 1.什么是数据库? 数据库(Database) 是按照数据结构来组织,存储和管理数据的仓库 数据库可以分为2大种类 关系型数据库(主流) PC端 Oracle My ...
- c#中的Cache缓存技术
1.HttpRuntime.Cache 相当于就是一个缓存具体实现类,这个类虽然被放在了 System.Web 命名空间下了.但是非 Web 应用也是可以拿来用的. 2.HttpContext.Cac ...
- Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)
Ajax跨域问题及解决方案 目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...
- day95:flask:SQLAlchemy数据库查询进阶&关联查询
目录 1.数据库查询-进阶 1.常用的SQLAlchemy查询过滤器 2.常用的SQLAlchemy查询结果的方法 3.filter 4.order_by 5.count 6.limit&of ...
- RDIFramework.NET 中多表关联查询分页实例
RDIFramework.NET 中多表关联查询分页实例 RDIFramework.NET,基于.NET的快速信息化系统开发.整合框架,给用户和开发者最佳的.Net框架部署方案.该框架以SOA范式作为 ...
- Python框架学习之Flask中的数据库操作
数据库操作在web开发中扮演着一个很重要的角色,网站中很多重要的信息都需要保存到数据库中.如用户名.密码等等其他信息.Django框架是一个基于MVT思想的框架,也就是说他本身就已经封装了Model类 ...
- python---django中form组件(2)自定制属性以及表单的各种验证,以及数据源的实时更新,以及和数据库关联使用ModelForm和元类
自定义属性以及各种验证 分析widget: class TestForm(forms.Form): user = fields.CharField( required = True, widget = ...
随机推荐
- [转] python提取计算结果的最大最小值及其坐标
python提取计算结果的最大最小值及其坐标 我们在fluent当中后处理的时候,可以通过fluent本身得到某些物理量的最大值和最小值,但是我们却无法确定这些最大值和最小值的具体位置.其实我们可以将 ...
- HDU6311 Cover (欧拉路径->无向图有最少用多少条边不重复的路径可以覆盖一个张无向图)
题意:有最少用多少条边不重复的路径可以覆盖一个张无向图 ,输出每条路径的边的序号 , 如果是反向就输出-id. 也就是可以多少次一笔画的方式画完这个无向图. 题解:我们已知最优胜的情况是整个图是欧拉图 ...
- 2017西安区域赛A / UVALive - 8512 线段树维护线性基合并
题意:给定\(a[1...n]\),\(Q\)次询问求\(A[L...R]\)的异或组合再或上\(K\)的最大值 本题是2017的西安区域赛A题,了解线性基之后你会发现这根本就是套路题.. 只要用线段 ...
- cmd 打开mysql客户端
- windows 系统C盘暴增
系统: Windows Server 2012R2 问题: C盘200G的空间,暴增剩余3G.但是查看仅有69G的空间占用. 根源:Windows的虚拟文件,驱动器分页. 解决方案: 我的电脑-> ...
- oracle 错误实例分析(ORA-01126)
问题描述 SQL> shutdown immediate ORA-01109: database not open Database dismounted. ORACLE instance sh ...
- 发送请求时params和data的区别
在使用axios时,注意到配置选项中包含params和data两者,以为他们是相同的,实则不然. 因为params是添加到url的请求字符串中的,用于get请求. 而data是添加到请求体(body) ...
- MyISAM的前缀压缩索引在索引块中的组织方式
纯粹自己的理解,哪位大佬看到了还请指正. 首先贴一张<高性能MySQL>中的一段话: 这句话的意思是说,MyISAM使用b+树组织索引.也就是说无论索引压缩与否,组织方式一定是B+树. 下 ...
- 解决IE9 IE8的跨域 请求问题
/// <summary> /// 根据url获取对应的HTML /// </summary> /// <param name="url">&l ...
- 昨天太晚了,今天教你用Debug模式来分析程序执行顺序
还是以昨天的XML文件解析来做栗子,希望通过这个好吃的栗子可以举一反三 学会用debug来看源码和找Bug 事件类型主要有五种START_DOCUMENT:xml头的事件类型 = 0END_DO ...