【Flask】Flask 学习笔记:留言板

“Flask学习笔记” 系列是博主学习《Flask Web开发实战》的学习记录。原书的作者为了读者方便,使用了 faker 生成了模拟数据,代码跑起来更加简单。我做了一些修改,连接了本地的数据库,在这里记录一下学习过程。

1.整体框架

看一下目录结构,采用了 MVC 框架。

在这里插入图片描述

2.配置文件(settings.py)

把相关配置信息放到一个单独的文件中。

import os

SECRET_KEY = os.getenv('SECRET_KEY', '123456789') #可以任意给一个字符串
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URI', 'mysql+pymysql://root:密码@127.0.0.1:3306/数据库名')

3.创建程序实例(init.py)

创建示例程序、初始化拓展等操作在此处完成。

  • flask_bootstrapflask_momentflask_sqlalchemy 是 flask 的拓展组件,我们后面会用到相关功能。
  • 利用 app.config.from_pyfile 导入配置文件。
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy

app = Flask('sayhello')

app.config.from_pyfile('settings.py')
app.jinja_env.trim_blocks = True  # 删除Jinjia2语句后的第一个空行
app.jinja_env.lstrip_blocks = True  # 删除Jinjia2语句所在行之前的空格和制表符

db = SQLAlchemy(app)
bootstrap = Bootstrap(app)
moment = Moment(app)

from sayhello import views, errors

4.数据库建模(models.py)

我们需要确定使用哪些表来存储数据。本次项目较为简单,一个表即可。

  • id:主键
  • name:留言者姓名
  • body:留言内容
  • timestamp:时间戳
from datetime import datetime
from sayhello import db

class Message(db.Model):
    __tablename__ = 'sayhello'  # 用到的表为sayhello
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20))
    body = db.Column(db.String(200))
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)

5.创建表单(forms.py)

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Length

class HelloForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(1, 20)])
    body = TextAreaField('Message', validators=[DataRequired(), Length(1, 200)])
    submit = SubmitField()

6.视图函数(views.py)

此处的视图函数有两个作用:

  1. 处理 GET 请求,从数据库中查询所有的消息记录,返回渲染后的包含消息列表的主页模板 index.html
  2. 处理 POST 请求,表单提交后,验证表单数据,通过验证后将数据保存到数据库中。使用 flash() 函数显示一条提示,然后重定向到 index 视图,渲染页面。
from flask import flash, render_template, url_for, redirect

from sayhello import app, db
from sayhello.forms import HelloForm
from sayhello.models import Message

@app.route('/', methods=['GET', 'POST'])
def index():
    form = HelloForm()
    if form.validate_on_submit():
        name = form.name.data
        body = form.body.data
        message = Message(body=body, name=name)  # 实例化模型类,创建记录
        db.session.add(message)  # 添加记录到数据库回会话
        db.session.commit()  # 提交会话
        flash('Your message have been sent to the world!')
        return redirect(url_for('index'))  # 重定向到index视图

    messages = Message.query.order_by(Message.timestamp.desc()).all()
    return render_template('index.html', form=form, messages=messages)

7.错误处理(errors.py)

错误处理函数也属于视图函数,只是单独分离出来作为一个文件。

from flask import render_template

from sayhello import app

@app.errorhandler(404)
def page_not_found(e):
    return render_template('errors/404.html'), 404

@app.errorhandler(500)
def internal_server_error(e):
    return render_template('errors/500.html'), 500

8.编写模板(templates)

8.1 基模板(base.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>{% block title %}Say Hello!{% endblock %}</title>
    <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css">
</head>

<body>
<main class="container">

    <header>
        <h1 class="text-center display-4">
            <a href="{{ url_for('index') }}" class="text-success"><strong>Say Hello</strong></a>
            <small class="text-muted sub-title">to the world</small>
        </h1>
    </header>
    
    {% for message in get_flashed_messages() %}
        <div class="alert alert-info">
            <button type="button" class="close" data-dismiss="alert">&times;</button>
            {{ message }}
        </div>
    {% endfor %}
    
    {% block content %}{% endblock %}
    
    <footer class="text-center">
        {% block footer %}
            <small> &copy; 2018 <a href="http://greyli.com" title="Written by Grey Li">Grey Li</a> /
                <a href="https://github.com/greyli/sayhello" title="Fork me on GitHub">GitHub</a> /
                <a href="http://helloflask.com" title="A HelloFlask project">HelloFlask</a>
            </small>
            <p><a id="bottom" href="#" title="Go Top">&uarr;</a></p>
        {% endblock %}
    </footer>
    
</main>

<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-3.2.1.slim.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
{{ moment.include_moment(local_js=url_for('static', filename='js/moment-with-locales.min.js')) }}
</body>
</html>

8.2 主页模板(index.html)

在主页模板 index.html 中,使用 render_form 宏渲染表单,然后迭代传入的 message 变量,渲染消息列表。

{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_form %}

{% block content %}
    <div class="hello-form">
        {{ render_form(form, action=request.full_path) }}
    </div>
    
    <h5>{{ messages|length }} messages
        <small class="float-right">
            <a href="#bottom" title="Go Bottom">&darr;</a>
        </small>
    </h5>
    
    <div class="list-group">
        {% for message in messages %}
            <a class="list-group-item list-group-item-action flex-column">
                <div class="d-flex w-100 justify-content-between">
                    <h5 class="mb-1 text-success">{{ message.name }}
                        <small class="text-muted"> #{{ loop.revindex }}</small>
                    </h5>
                    <small data-toggle="tooltip" data-placement="top"
                           data-timestamp="{{ message.timestamp.strftime('%Y-%m-%dT%H:%M:%SZ') }}"
                           data-delay="500">
                        {{ moment(message.timestamp).fromNow(refresh=True) }}
                    </small>
                </div>
                <p class="mb-1">{{ message.body }}</p>
            </a>
        {% endfor %}
    </div>
{% endblock %}

8.3 错误页面

8.3.1 404.html

{% extends "base.html" %}

{% block title %}404 Error{% endblock %}

{% block content %}
    <p class="text-center">Page Not Found</p>
{% endblock %}

{% block footer %}
    <a href="{{ url_for('index') }}">&larr; Go Back</a>
{% endblock %}

8.3.2 500.html

{% extends "base.html" %}

{% block title %}500 Error{% endblock %}

{% block content %}
    <p class="text-center">Internal Server Error</p>
{% endblock %}

{% block footer %}
    <a href="{{ url_for('index') }}">&larr; Go Back</a>
{% endblock %}

9.程序入口(manage.py)

from sayhello import app

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

10.结果展示

在这里插入图片描述

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

G皮T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值