美文网首页
Flask 极简 CRUD 操作

Flask 极简 CRUD 操作

作者: Stone0823 | 来源:发表于2018-12-18 22:36 被阅读54次

    一个简单的 CRUD 操作基本可以看出某个开发框架和平台的特点。Flask 作为一个微框架,在开发一些小型应用的时候非常合适。本文试图从开发一个简单的 Notebook 应用,说明 Flask 开发的基本模式。除 Flask 模块外,本次用到以下插件:

    • Flask-SQLAlchemy (基于 SQLAlchemy 的扩展,操作数据库)
    • Flask-WTF (一个表单插件,让 HTML 表单编写更加简单)

    Flask 工程文件的结构

    Flask 开发并没有业界权威的工程文件结构,但还是有主流的做法。参考网上的文章和代码,我准备采用如下的结构

    project-folder/
        app / 
            templates /       <---- 模版文件
            static /          <---- 静态文件,比如 css 文件
             __init__.py      <---  把 app 文件夹作为一个 package,在此文件中创建 flask app
            controllers.py    <--- 数据库操作
            models.py         <--- 数据库表与 model 的映射
            views.py          <---  视图函数和路由
    
        configs.py            <--- app 配置
        db_scripts.py         <--- 数据库脚本
        server.py             <--- 服务器端启动入口
    

    配置

    我们先从配置开始,因为主要为了说明 Flask CRUD 的要素,所以配置只有最基本的两项,连 SECRET_KEY 都省了。从 Windows 环境变量 获取数据连接的 URI。

    # configs.py
    
    import os
    
    SQLALCHEMY_DATABASE_URI = os.getenv('DB_URI')
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    

    数据库 CRUD 操作

    使用 Flask-SQLAlchemy 进行数据库的 CRUD 操作。首先在 app/models.py 中定义 Model 的结构,映射到数据表和字段:

    # models.py
    
    from flask_sqlalchemy import SQLAlchemy
    
    db = SQLAlchemy()
    
    class Notes(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        body = db.Column(db.Text)
    
        def __repr__(self):
            return 'Note body: {}'.format(self.body)
    

    然后在 app/controllers.py 文件中,定义数据库的 CRUD 操作的五个方法:

    # controllers.py
    
    from app.models import db, Notes
    from sqlalchemy import desc
    
    class NotesDao():
        def create_note(self, note_body):
            new_note = Notes(body=note_body)
            db.session.add(new_note)
            db.session.commit()
    
            return new_note
    
    
        def update_note(self, note):
            modified_note = Notes.query.get(note.id)
            db.session.commit()
    
            return modified_note
    
    
        def delete_note(self, note):
            note_to_delete = Notes.query.get(note.id)
            db.session.delete(note_to_delete )
            db.session.commit()
    
            return True
    
    
        def list_all(self):
            return Notes.query.order_by(desc(Notes.id)).all()
    
    
        def get_note(self, id):
            return Notes.query.get(id)
    

    定义视图函数

    app/views.py 文件中,定义蓝图 (blueprint) 和视图函数

    
    from flask import request, render_template, Blueprint, flash, redirect, url_for
    from app.controllers import NotesDao
    from app.forms import *
    
    
    # 定义蓝图
    notesbp = Blueprint('notesbp', __name__, template_folder='templates')
    
    @notesbp.route('/')
    def index():
    
        noteservice = NotesDao()
    
        # return book list to front end
        notes = noteservice.list_all()
        return render_template('index.html', notes=notes)
    
    
    @notesbp.route('/new', methods=['GET', 'POST'])
    def new_note():
        form = NewNoteForm()
    
        if request.method == 'POST':
            body = request.form['body']
            noteservice = NotesDao()
            noteservice.create_note(body)
    
            return redirect(url_for('notesbp.index'))
    
        return render_template('new_note.html', form=form)
    
    
    @notesbp.route('/edit/<int:note_id>', methods=['GET', 'POST'])
    def edit_note(note_id):
        form = EditNoteForm()
        note = NotesDao().get_note(note_id)
    
        if request.method == 'POST':
            body = request.form['body']
            note.body = body
            NotesDao().update_note(note)
    
            return redirect(url_for('notesbp.index'))
    
        form.body.data = note.body
        return render_template('edit_note.html', form=form)
    
    
    @notesbp.route('/delete/<int:note_id>', methods=['GET'])
    def delete_note(note_id):
        notesdao = NotesDao()
        note = notesdao.get_note(note_id)
        notesdao.delete_note(note)
    
        return redirect(url_for('notesbp.index'))
    

    说明:blueprint 是 Flask 代码模块化的一种工具,本例中将当前模块命名为 notesbp,视图函数利用 blueprint 映射路由, url_for() 函数利用 blueprint 查找视图函数 。

    HTML 文件

    视图函数中关联的 html 文件,放在 templates 文件夹中。

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Flask basic CRUD</title>
        <link rel="stylesheet" type="text/css" href="../static/styles.css">
    </head>
    <body>
        <a href="{{ url_for('notesbp.new_note') }}">New note</a>
    
        <h4> {{ notes|length }} Notes: </h4>
    
        <table>
            <tr>
                <th>ID</th>
                <th>Body</th>
                <th>Action</th>
            </tr>
    
            {% for note in notes %}
                <tr>
                    <td> {{note.id}} </td>
                    <td> {{note.body}} </td>
                    <td>
                        <a href="{{ url_for('notesbp.edit_note', note_id=note.id) }}">Edit</a>
                        <a href="{{ url_for('notesbp.delete_note', note_id=note.id) }}">Delete</a>
                    </td>
                </tr>
            {% endfor %}
        </table>
    </body>
    </html>
    

    edit_note.htmlnew_note.html 内容相同

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>New note</title>
    </head>
    <body>
        <h2>New note</h2>
    
        <form method="POST">
            {{ form.body(rows='10',cols='100') }}<br/>
            {{ form.submit }}
        </form>
    </body>
    </html>
    

    为简化 html 文件的编写,使用了 flask-wtf 表单,表单的代码放在 app/forms.py 文件中:

    from wtforms import Form, TextAreaField, SubmitField
    
    class NewNoteForm(Form):
        body = TextAreaField('body')
        submit = SubmitField('Save')
    
    class EditNoteForm(Form):
        body = TextAreaField('body')
        submit = SubmitField('Update')
    

    使用工厂函数创建 app

    代码放在 app/__init__.py 文件中:

    from flask import Flask
    import configs
    from app.models import db
    from app.views import notesbp
    
    
    def create_app():
        app = Flask(__name__)
    
        # 加载配置
        app.config.from_object(configs)
    
        # 初始化db
        db.app = app
        db.init_app(app)
    
        # 注册蓝图
        app.register_blueprint(notesbp)
    
        return app
    

    生成数据库表

    先用 SQL 语句 create database xxx charset utf8; 创建数据库,然后运行 db_scripts.py 代码创建表:

    from app.models import db
    from app import create_app
    
    app = create_app()
    db.app = app
    db.init_app(app)
    
    if __name__ == '__main__':
        db.drop_all()
        db.create_all()
        print ('Done')
    

    启动文件

    后端程序通过 server.py 启动,代码如下:

    from app import create_app
    
    app = create_app()
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    参考

    本文的代码:请点击Github

    相关文章

      网友评论

          本文标题:Flask 极简 CRUD 操作

          本文链接:https://www.haomeiwen.com/subject/ebhlkqtx.html