表格模型类

3.1概念OMP

Object-Relation Mapping对象关系映射,调用模型对象生成对应的sql语句,通过ORM配置不同的数据库。
flasksqlalchemy 是一个简化了 SQLAlchemy 操作的flask扩展
优点:
	对数据库的操作都转化成对类属性和方法的操作,不用编写各种数据库的 sql语句,只需要面向对象编程, 不需要面向数据库编写代码;实现了数据模型与数据库的解耦, 屏蔽了不同数据库操作上的差异,通过简单的配置就可以轻松更换数据库, 而不需要修改代码不在关注用的是 mysql,oracle等
缺点:
	相比较直接使用SQL语句操作数据库,有性能损失,根据对象的操作转换成SQL语句,根据查询的结果转化成对象, 在映射过程中有性能损失.

3.2安装

框架安装 pip install flask-sqlalchemy
操作mysql数据库 pip install flask-mysqldb

3.3常用字段类型

Integer 普通整数,一般是32位
Float 浮点数
String(字符串长度) 字符串
Boolean 布尔类型
Enum 枚举类型
Text 文本类型
Date 日期
DateTime 日期和时间
Time 时间

3.4常用字段约束

primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值

3.5常用关系选项

backref 在关系的另一模型中添加反向引用
secondary 指定多对多关系中关系表的名字

3.6创建一个应用程序对象

from flask import Flask
app = Flask(__name__)

3.7数据库连接配置

数据库使用URL指定
	app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
动态追踪修改设置
	app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
查询时会显示原始SQL语句
	app.config['SQLALCHEMY_ECHO'] = True

3.8初始化数据库

先初始化一个db对象
	from flask.ext.sqlalchemy import SQLAlchemy
	db = SQLAlchemy()
再调用init_app()方法初始化数据库
	db.init_app(app)
可以合在一起
	db.SQLAlchemy(app)
根据模型用来创建以及删除表格的方法
	db.drop_all()
	db.create_all()	
利用对象的会话(session)来操作数据库	
Model声明基类,有个query属性,可以用来查询模型

3.9增删改操作

3.9.1增
	db.session.add(模型对象)
	db.session.add_all(模型对象列表)
3.9.2删
	db.session.delete(模型对象)
3.9.3改
	先查询到要修改的对象,比如是user
	user.name=“要修改成的名字”
	或者
	User.query.filter_by(name=“xxx”).update({“name”:”要修改成的名字”})
3.9.4注意
	所有操作都要提交
	db.session.commit()
	失败后回滚
	db.session.rollback()

3.10定义模型类

模型基类
-------------------------------------------------
class BaseModel(object):
	"""模型基类,为每个模型添加创建时间与更新时间"""
	create_time = db.Column(db.DateTime, default=datetime.now)  # 记录的创建时间
	update_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)  # 记录的更新时间
-------------------------------------------------
多对多关系表
-------------------------------------------------
# 用户收藏表,建立用户与其收藏新闻多对多的关系
tb_user_collection = db.Table(
	"info_user_collection",  # 表名
	db.Column("user_id", db.Integer, db.ForeignKey("info_user.id"), primary_key=True),  # 新闻编号
	db.Column("news_id", db.Integer, db.ForeignKey("info_news.id"), primary_key=True),  # 分类编号
	db.Column("create_time", db.DateTime, default=datetime.now)  # 收藏创建时间
)

# 用户粉丝表,建立用户与其粉丝多对多的关系
tb_user_follows = db.Table(
	"info_user_fans",  # 表名
	db.Column('follower_id', db.Integer, db.ForeignKey('info_user.id'), primary_key=True),  # 粉丝id
	db.Column('followed_id', db.Integer, db.ForeignKey('info_user.id'), primary_key=True)  # 被关注人的id
)
-------------------------------------------------
用户模型类
-------------------------------------------------
class User(BaseModel, db.Model):
	"""用户模型类"""
	__tablename__ = "info_user"

	id = db.Column(db.Integer, primary_key=True)  # 用户编号
	nick_name = db.Column(db.String(32), unique=True, nullable=False)  # 用户昵称
	password_hash = db.Column(db.String(128), nullable=False)  # 加密的密码
	mobile = db.Column(db.String(11), unique=True, nullable=False)  # 手机号
	avatar_url = db.Column(db.String(256))  # 用户头像路径
	last_login = db.Column(db.DateTime, default=datetime.now)  # 最后一次登录时间
	is_admin = db.Column(db.Boolean, default=False)  # 管理员
	signature = db.Column(db.String(512))  # 用户签名
	gender = db.Column(  # 用户性别
		db.Enum(
			"MAN",  # 男
			"WOMAN"  # 女
		),
		default="MAN")
		
	# 当前用户收藏的所有新闻,secondary指定多对多关系中关系表的名字
	# User.collection_news可以查到所有用户收藏新闻
	collection_news = db.relationship("News", secondary=tb_user_collection, lazy="dynamic")  # 用户收藏的新闻
	
	# 用户所有的粉丝,添加了反向引用followed,
	# User.followers可以查到用户所有粉丝;User.followed可以找到都关注了哪些人
	followers = db.relationship('User',
		secondary=tb_user_follows,
		primaryjoin=id == tb_user_follows.c.followed_id,
		secondaryjoin=id == tb_user_follows.c.follower_id,
		backref=db.backref('followed', lazy='dynamic'),
		lazy='dynamic')
								
	# 当前用户所发布的新闻
	# User.news_list可以查询到用户发布的新闻类表;New.user可以找到新闻的作者
	news_list = db.relationship('News', backref='user', lazy='dynamic')							

	# password 加密处理
	@property
	def password(self):
		raise AttributeError("当前属性不允许读取")

	# 用对象.方法名调用passwoed属性
	@password.setter
	def password(self, value):
		# self.password_hash 对value加密
		self.password_hash = generate_password_hash(value)

	def check_password(self, password):
		"""校验密码"""
		return check_password_hash(self.password_hash, password)

	def to_dict(self):
		resp_dict = {
			"id": self.id,
			"nick_name": self.nick_name,
			"avatar_url": constants.QINIU_DOMIN_PREFIX + self.avatar_url if self.avatar_url else "",
			"mobile": self.mobile,
			"gender": self.gender if self.gender else "MAN",
			"signature": self.signature if self.signature else "",
			"followers_count": self.followers.count(),
			"news_count": self.news_list.count()
		}
		return resp_dict

	# strftime()时间输出格式
	def to_admin_dict(self):
		resp_dict = {
			"id": self.id,
			"nick_name": self.nick_name,
			"mobile": self.mobile,
			"register": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
			"last_login": self.last_login.strftime("%Y-%m-%d %H:%M:%S"),
		}
		return resp_dict
-------------------------------------------------
新闻模型
-------------------------------------------------
class News(BaseModel, db.Model):
	"""新闻模型"""
	__tablename__ = "info_news"

	id = db.Column(db.Integer, primary_key=True)  # 新闻编号
	title = db.Column(db.String(256), nullable=False)  # 新闻标题
	source = db.Column(db.String(64), nullable=False)  # 新闻来源
	digest = db.Column(db.String(512), nullable=False)  # 新闻摘要
	content = db.Column(db.Text, nullable=False)  # 新闻内容
	clicks = db.Column(db.Integer, default=0)  # 浏览量
	index_image_url = db.Column(db.String(256))  # 新闻列表图片路径
	category_id = db.Column(db.Integer, db.ForeignKey("info_category.id"))  # 新闻分类id外键
	user_id = db.Column(db.Integer, db.ForeignKey("info_user.id"))  # 当前新闻的作者id外键
	status = db.Column(db.Integer, default=0)  # 新闻状态 0审核通过,1审核中,-1审核不通过
	reason = db.Column(db.String(256))  # 未通过原因,status = -1 的时候使用
	
	# 当前新闻的所有评论,新闻是一,评论是多,News.comments可以查到新闻所有评论
	comments = db.relationship("Comment", lazy="dynamic")

	def to_review_dict(self):
		resp_dict = {
			"id": self.id,
			"title": self.title,
			"create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
			"status": self.status,
			"reason": self.reason if self.reason else ""
		}
		return resp_dict

	def to_basic_dict(self):
		resp_dict = {
			"id": self.id,
			"title": self.title,
			"source": self.source,
			"digest": self.digest,
			"create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
			"index_image_url": self.index_image_url,
			"clicks": self.clicks,
		}
		return resp_dict

	def to_dict(self):
		resp_dict = {
			"id": self.id,
			"title": self.title,
			"source": self.source,
			"digest": self.digest,
			"create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
			"content": self.content,
			"comments_count": self.comments.count(),
			"clicks": self.clicks,
			"category": self.category.to_dict(),   # 新闻属于的分类对象.方法
			"index_image_url": self.index_image_url,
			"author": self.user.to_dict() if self.user else None  # 新闻的作者对象.方法
		}
		return resp_dict
-------------------------------------------------
评论点赞模型
-------------------------------------------------
class CommentLike(BaseModel, db.Model):
	"""评论点赞模型"""
	__tablename__ = "info_comment_like"
	
	comment_id = db.Column("comment_id", db.Integer, db.ForeignKey("info_comment.id"), primary_key=True)  # 评论编号
	user_id = db.Column("user_id", db.Integer, db.ForeignKey("info_user.id"), primary_key=True)  # 用户编号
-------------------------------------------------
新闻分类模型
-------------------------------------------------
class Category(BaseModel, db.Model):
	"""新闻分类"""
	__tablename__ = "info_category"

	id = db.Column(db.Integer, primary_key=True)  # 分类编号
	name = db.Column(db.String(64), nullable=False)  # 分类名
	# Category.news_list分类的新闻列表,News.category可以查询到新闻的分类
	news_list = db.relationship('News', backref='category', lazy='dynamic')

	def to_dict(self):
		resp_dict = {
			"id": self.id,
			"name": self.name
		}
		return resp_dict

3.11查询操作

Model声明基类,有个query属性,通过query对对象数据库进行查询。

3.11.1过滤器
	逻辑查询
		!逻辑非
			返回名字不等于wang的所有数据
			User.query.filter(User.name!='wang').all()
		and_逻辑与
			需要导入and_,可以省略
			from sqlalchemy import and_
			User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()
			User.query.filter(User.name!='wang',User.email.endswith('163.com')).all()
		or_逻辑或
			from sqlalchemy import or_
			User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()
		not_ 取反
			from sqlalchemy import not_
			User.query.filter(not_(User.name=='chen')).all()
		查询在  in_
			from sqlalchemy import or_
			查询id为 [1, 3, 5, 7, 9] 的用户列表
			User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()
	精确查询
		filter_by精确查询
			参数是值
			User.query.filter_by(name='wang').all()
	模糊查询
		filter模糊查询
			返回名字结尾字符为g的所有数据
			User.query.filter(User.name.endswith('g')).all()
		endswith()
		contains()
		startswith()
			参数字符串
			查询以.....结尾,查询包含什么,查询以.....开始
	其他过滤器
		limit 使用指定的值限定原查询返回的结果
		offset() 偏移原查询返回的结果,返回一个新查询
		order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
		group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

3.11.2执行器
	all()
		无参数,返回查询到的所有对象
		User.query.all()
	get():参数为主键
		参数是主键id,不存在没有返回内容
		User.query.get()
	count()
		没有参数,查询数量
		User.query.count()
	first()
		无参数,返回查询到的第一个对象
		User.query.first()
	first_or_404()
		返回查询的第一个结果,如果未查到,返回404
	get_or_404() 
		返回指定主键对应的行,如不存在,返回404
	
3.11.3分页查询
	每页3个,查询第2页的数据
	paginate = User.query.paginate(2, 3) 
	# 第1个参数代表查询第几页,第2个参数代表每页几个
	paginate.items 当前页数据
	paginate.pages 总页数
	paginate.page  当前页	
	
3.11.4查询id为4的用户[3种方式]
	User.query.filter_by(id=4).first()
	User.query.filter(User.id == 4).first()
	User.query.get(4)	
	
3.11.5排序查询
	反序		User.query.order_by(User.email.desc()).all()
	正序(默认)User.query.order_by(User.email).all()	

3.12数据库迁移

3.12.1概念
	作用:追踪数据库模式的变化,然后把变动应用到数据库中
	安装Flask-Migrate扩展:pip install flask-migrate
	扩展提供了一个MigrateCommand类,对象可以注册到flask-script的manager对象上
		# 创建命令行对象,用命令行控制qpp
		manager = Manager(app)
		# 将app与db关联
		Migrate(app, db)
		# 将命令迁移到manager上
		manager.add_command('db', MigrateCommand)
	
3.12.2创建迁移仓库
	初始化命令 python database.py db init
	创建migrations文件夹,所有迁移文件都放在里面

3.12.3创建迁移脚本
	python 文件 db migrate -m '注释'
	
3.12.4更新数据库
	python 文件 db upgrade

3.12.4查看历史版本
	python 文件 db history

3.12.4进入历史版本
	python 文件 db downgrade(upgrade) 版本号

猜你喜欢

转载自blog.csdn.net/weixin_42932562/article/details/82947358