Flask 極簡 CRUD 操作

一個(gè)簡單的 CRUD 操作基本可以看出某個(gè)開發(fā)框架和平臺的特點(diǎn)。Flask 作為一個(gè)微框架,在開發(fā)一些小型應(yīng)用的時(shí)候非常合適。本文試圖從開發(fā)一個(gè)簡單的 Notebook 應(yīng)用,說明 Flask 開發(fā)的基本模式。除 Flask 模塊外,本次用到以下插件:

  • Flask-SQLAlchemy (基于 SQLAlchemy 的擴(kuò)展,操作數(shù)據(jù)庫)
  • Flask-WTF (一個(gè)表單插件,讓 HTML 表單編寫更加簡單)

Flask 工程文件的結(jié)構(gòu)

Flask 開發(fā)并沒有業(yè)界權(quán)威的工程文件結(jié)構(gòu),但還是有主流的做法。參考網(wǎng)上的文章和代碼,我準(zhǔn)備采用如下的結(jié)構(gòu)

project-folder/
    app / 
        templates /       <---- 模版文件
        static /          <---- 靜態(tài)文件,比如 css 文件
         __init__.py      <---  把 app 文件夾作為一個(gè) package,在此文件中創(chuàng)建 flask app
        controllers.py    <--- 數(shù)據(jù)庫操作
        models.py         <--- 數(shù)據(jù)庫表與 model 的映射
        views.py          <---  視圖函數(shù)和路由

    configs.py            <--- app 配置
    db_scripts.py         <--- 數(shù)據(jù)庫腳本
    server.py             <--- 服務(wù)器端啟動(dòng)入口

配置

我們先從配置開始,因?yàn)橹饕獮榱苏f明 Flask CRUD 的要素,所以配置只有最基本的兩項(xiàng),連 SECRET_KEY 都省了。從 Windows 環(huán)境變量 獲取數(shù)據(jù)連接的 URI。

# configs.py

import os

SQLALCHEMY_DATABASE_URI = os.getenv('DB_URI')
SQLALCHEMY_TRACK_MODIFICATIONS = False

數(shù)據(jù)庫 CRUD 操作

使用 Flask-SQLAlchemy 進(jìn)行數(shù)據(jù)庫的 CRUD 操作。首先在 app/models.py 中定義 Model 的結(jié)構(gòu),映射到數(shù)據(jù)表和字段:

# 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 文件中,定義數(shù)據(jù)庫的 CRUD 操作的五個(gè)方法:

# 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)

定義視圖函數(shù)

app/views.py 文件中,定義藍(lán)圖 (blueprint) 和視圖函數(shù)


from flask import request, render_template, Blueprint, flash, redirect, url_for
from app.controllers import NotesDao
from app.forms import *


# 定義藍(lán)圖
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 代碼模塊化的一種工具,本例中將當(dāng)前模塊命名為 notesbp,視圖函數(shù)利用 blueprint 映射路由, url_for() 函數(shù)利用 blueprint 查找視圖函數(shù) 。

HTML 文件

視圖函數(shù)中關(guān)聯(lián)的 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 內(nèi)容相同

<!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')

使用工廠函數(shù)創(chuàng)建 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)

    # 注冊藍(lán)圖
    app.register_blueprint(notesbp)

    return app

生成數(shù)據(jù)庫表

先用 SQL 語句 create database xxx charset utf8; 創(chuàng)建數(shù)據(jù)庫,然后運(yùn)行 db_scripts.py 代碼創(chuàng)建表:

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')

啟動(dòng)文件

后端程序通過 server.py 啟動(dòng),代碼如下:

from app import create_app

app = create_app()

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

本文源代碼: https://github.com/stonewm/python-practice-projects/tree/master/Flask/Notebook-v1.0

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容