天天看点

FLASK数据库模型

云想衣裳花想容,春风拂槛露华浓。

SQLAlchemy 是一个基于 Python 实现的 ORM 库,是一种 面对对象 的数据库编程框架 (关系对象映射)。

快速入门文档

http://www.pythondoc.com/flask-sqlalchemy/quickstart.html

安装

pip install sqlalchemy
           

复制

在 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 -------------------