SQLAlchemy 是一个基于 Python 实现的 ORM 库,是一种 面对对象 的数据库编程框架 (关系对象映射)。
快速入门文档 http://www./flask-sqlalchemy/quickstart.html
安装
在 Flask 项目中的 URI 配置 class Config: SECRET_KEY ="abc_caonima_wocao" # 随机 SECRET_KEY SQLALCHEMY_COMMIT_ON_TEARDOWN = True # 自动提交 SQLALCHEMY_TRACK_MODIFICATIONS = True # 自动sql
DEBUG = True # debug模式 SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://%s:%s@%s:%s/%s' % (DB_USERNAME, DB_PASSWORD,DB_HOST, DB_PORT, DB_NAME) #数据库URL
在初始化项目中连接
app = Flask(__name__,template_folder='templates',static_folder='static') app.config.from_object(Config)
db = SQLAlchemy(app) db.init_app(app)
这样就把 数据库 和 Flask实例联系起来了,这里使用 Mysql 建立数据库模型 所谓数据库模型,说白了就是建立数据库中所需的具体字段,包括字段名称,类型,限制条件等等
比如在个人博客中,我们需要有文章列表,也需要有文章详情的数据库模型。
编写模型对象 class Article(db.Model): __tablename__ = 'article' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(32)) author = db.Column(db.String(32)) img_url = db.Column(db.Text, nullable=False) content = db.Column(db.Text, nullable=False) tag = db.Column(db.String(64), nullable=True) uuid = db.Column(db.Text, nullable=False) create_time = db.Column(db.DateTime, nullable=True, default=datetime.now) uid = db.relationship('Article_Detail', backref='article')
def __repr__(self): return '<Article %r>' % self.title
这样就实现了文章的数据库所需字段
id:数据库id,主键
title:文章标题,字符类型,后面声明长度
author:作者,字符类型
img_url:图片,text类型
content:文章简介
tag:所属标签
uuid:文章唯一标识id
create_time:创建时间,detatime类型 uid:反向代理,通过关联的名称表可以得到 article表中的属性 Article_Detail模型 class Article_Detail(db.Model): __tablename__ = 'article_detail' id = db.Column(db.Integer, primary_key=True) d_content=db.Column(db.Text,nullable=False) uid = db.Column(db.Integer, db.ForeignKey('article.id'))
def __repr__(self): return '<Article_Detail %r>' % self.title
id:数据库id,主键 d_content:详情文章内容,文本类型
uid:外键,关联到 article 表 id 通过 relationship 和 ForeignKey 把文章和文章详情表联系起来,在编写文章详情的时候,通过 uid 选择是哪一篇文章的详情即可。 对于个人博客而言,模型的关联并没有很复杂,一般是 一对多 的操作就可以搞定,当然如果是论坛或者社区的话,会用到 多对一 和 多对多 的数据库操作 ,不做详细介绍。
增删改查
SQLAlchemy 之所以这么流行,在 Flask 中地位如此之高,基于它是面对对象的数据库编程。 所以,对于数据查询,添加等操作也是非常的简单。 查询文章列表: @home.route('/') def index(): init_list= Article.query.order_by(db.desc(Article.create_time)).all() return render_template('home/index.html', datas=init_list)
可以看到,查询所有文章的语句,这里是按照创建的时间排序的,注意到desc(Article.create_time),然后将所得列表传给前端页面,渲染完成。 再来看看根据 id 查询文章详情内容的路由实现: @home.route('/article/<uuid>') def query_detail(uuid): base_path = os.path.abspath('app/templates/article/') old_file = os.listdir(base_path)[0] old_path = os.path.join(base_path, old_file) file_path = os.path.abspath('app/templates/article/{}.html'.format(uuid)) if not os.path.exists(file_path): log_v.debug("[-] File does not exist, renaming !!!") os.rename(old_path, file_path) form = CommentForm() searchForm = SearchForm() article_res = Article.query.filter_by(uuid=uuid).first() article_detail_res = Article_Detail.query.filter_by(uid=article_res.id).first() return render_template('article/{}.html'.format(uuid), a_data=article_res, d_data=article_detail_res, form=form, searchForm=searchForm)
思路设计:
在templates模板目录中新建一个article 用于存放文章详情页的html文件,并且索引到这个目录中,在这个目录中只有一个 html 文件,我们只需要向这个html文件填入查询回来的数据即可。
由于文章列表需要根据文章的 uuid 来跳转到详情页,所以这个 html文件的名称需要 rename 为跳转文章的 uuid,才能正确跳转。 最后,根据 uuid 查询到文章,再由文章的 id 查询到详情文章内容,渲染到详情页。 是不是及其简单,所以前期的工作主要是数据库模型字段的设计,还有迁移到数据库中,也就是创建表,让其工作。
数据库迁移 使用 flask_migrate 扩展可以非常简单的进行数据库的迁移 # coding:utf8 from datetime import datetime from flask_migrate import Migrate, MigrateCommand from app import app from app.models import db from flask_script import Manager, Server
manage = Manager(app)
# 迁移 Migrate(app,db) manage.add_command('db',MigrateCommand)
if __name__ == "__main__": manage.run()
''' 初始化 python manage.py db init
创建迁移 python manage.py db migrate
执行迁移 python manage.py db upgrade '''
黑窗口 执行命令 python manage.py db init
初始化数据库,执行之后会在主 app 目录中生成一个 migrations 目录,里面包含了一些创建的信息,如 版本号 和 操作脚本。 然后执行 python manage.py db migrate 迁移数据库,在数据库中真正创建表字段 最后执行 python manage.py db upgrade 让其生效 PS:在往后的每一次更改数据库模型中的字段之后,只需要执行后两个命令即可。
关于数据库回滚 # -*- coding:utf-8 -*- import os from datetime import datetime from sqlalchemy import or_ from app import app,db from app.Logger.logger import log_v from app.forms import CommentForm, SearchForm from app.tools.getIdAddr import getAddr from app.home.home import home from flask import render_template, request, redirect from app.models import Article, Article_Detail, Global_V, Comment,UserIP
@home.route('/postComment/<uuid>', methods=['GET', 'POST']) def postComment(uuid): # app.config.update(SECRET_KEY=os.urandom(24)) # log_v.debug("[*] UPDATE SECRET_KEY") log_v.debug("[+] Add Comment")
form = CommentForm() # 字段必须完整 if request.method == "POST" and form.validate_on_submit(): theme = form.theme.data content = form.content.data email = form.email.data csrf_token = form.csrf_token.data t_md = request.form.get("t_md","") if all([theme, email, content, csrf_token, t_md]): try: add_comment = Comment(theme=theme, email=email, content=content, uuid=uuid) db.session.add(add_comment) db.session.commit() return "评论成功" except Exception as e: db.session.rollback() return "评论失败"
finally: log_v.debug("Comment Done " + theme + ' ' + ' ' + content + ' ' + email + ' ' + t_md)
else: return "参数不齐" else: return redirect('/article/{}'.format(uuid))
数据库的回滚是十分有必要的,用于处理程序或者数据错误,让程序回到上一次的状态,这就是所谓的数据库回滚,否则很可能会造成死锁或者超时,这是非常可怕的。 所以,请回滚!!! ------------------- End -------------------
|