初步flask运行

写下程序blog.py并运行

from flask import Flask

app=Flask(__name__)

@app.route('/')#使用装饰器装饰根目录
def index():
    return 'Blog for me'

在项目(blog.py)所在文件夹中打开cmd,设置如下:

cd C:\Users\Pondsi\Desktop\HARD_LEARN\develop_flask\FLASK_START
set FLASK_APP=blog.py
set FLASK_ENV=development

并输入以下指令开始运行

flask run

如果确认是development环境且debug mode on,修改blog.py的index return内容时 如果刷新网页改变对应内容,则至此成功

样式导入

在blog.py所在文件夹建立templates文件夹,放入对应html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Sharing blog</title>
    </head>

    <body>
        <header>
            <h1>欢迎访问Sharing Blogs</h1>
            <nav>
                <!-- 这里可以放导航链接 -->
            </nav>
        </header>
        
        <main>
            <p>你可以在此分享你的一切</p>
        </main>

        <footer>
            Sharing Blogs
            <!-- 页脚内容 -->
        </footer>
    </body>
</html>

修改blog.py,import render_templates,并返回对应html

在html的head中加入link

<link rel="stylesheet" href="{{url_for('static',filename='css/style.css')}}">

在static的css中编写对应h1样式

h1{
    border:auto #eee solid;
    color: brown;
    text-align: center;
    padding: auto;
}

使用bootsrap样式

下载bootstrap内容放入static的css和js中 往templates中加入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">
    <link rel="stylesheet" href="{{url_for('static',filename='css/bootstrap.min.css')}}">
    <title>{%block title %}{%endblock%}</title>
</head>

<body>
    <nav class="navbar navbar-expand-md navbar-light bg-light">
        <a class="navbar-brand" href="{{url_for('index')}}">
            Sharing Blogs
        </a>

        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
            aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
                <li class="nav-item active">
                    <a class="nav-link" href="#">关于sharing</a>
                </li>
            </ul>
        </div>
    </nav>
    <div class="container">
        {% block content %}{% endblock %}
    </div>

    <script src="{{url_for('static',filename='js/jquery.slim.min.js')}}"></script>
    <script src="{{url_for('static',filename='js/proper.min.js')}}"></script>
    <script src="{{url_for('static',filename='js/bootstrap.min.js')}}"></script>
</body>

</html>

此时,便可直接根据控制字块调用以及修改博客内容

{% extends 'base.html' %}

{% block content %}
I am a student.
{% endblock %}

使用sqlite3构造数据库

创建db.sql进行表形态定义

DROP TABLE IF EXISTS posts;

CREATE TABLE posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    title TEXT NOT NULL,
    content TEXT NOT NULL
);

初始化数据库,并尝试链接数据库获取句柄并插入数据

import sqlite3

conn=sqlite3.connect('database.db')

with open('db.sql') as f:
    conn.executescript(f.read())

#创建执行句柄,用以执行语句
cur=conn.cursor()

cur.execute("INSERT INTO posts(title,content) VALUES (?,?)",
            ('学习Flask1','Sharing your flask part 1'))
cur.execute("INSERT INTO posts(title,content) VALUES (?,?)",
            ('学习Flask2','Sharing your flask part 2'))

conn.commit()
conn.close()

更改blog.py,加入数据库读取部分,将数据库内容装入index.html

from flask import Flask,render_template
import sqlite3

app=Flask(__name__)

def get_db_conn():
    conn=sqlite3.connect('database.db')
    conn.row_factory=sqlite3.Row
    return conn

@app.route('/')#使用装饰器装饰根目录
def index():
    conn= get_db_conn()
    posts=conn.execute('select * from posts').fetchall()
    return render_template('index.html',posts=posts)

展示文章列表

修改index.html,在标题下加入博客遍历,并加入创建时间戳与底部横线美化

{% extends 'base.html' %}

{% block content %}
<h1>欢迎访问Sharing Blogs</h1>

{% for post in posts %}
<a href="{{ url_for('post', id=post['id']) }}">
    <h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{post['created']}}</span>
<hr>
{% endfor %}

{% endblock %}

新建文章表单

在templates文件夹中新建new.html,在blog.py加入对应函数

// ... existing code ...
@app.route('/posts/new',methods=['GET','POST'])
def new():
    return render_template('new.html')
// ... existing code ...

构建new.html内容如下

{% extends 'base.html' %}

{% block content %}
<h1>{%block title %}New Blog{% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="title">标题</label>
        <input type="text" class="form-control" id="title" name="title" value="{{ request.form.title }}">
    </div>

    <div class="form-group">
        <label for="content">内容</label>
        <textarea class="form-control" placeholder="博客内容" name="content">{{ request.form['content'] }}</textarea>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">提交</button>
    </div>
</form>
{% endblock %}

文件详情页

在templates文件夹中新建post.html,在blog.py加入对应函数

// ... existing code ...
def get_post(post_id):
    conn=get_db_conn()
    post=conn.execute('select * from posts where id=?',(post_id,)).fetchone()
    conn.close()
    return post
// ... existing code ...
@app.route('/posts/<int:post_id>')
def post(post_id):
    post=get_post(post_id)
    return render_template('post.html',post=post)
// ... existing code ...

构建post.html内容如下,为美观加入时间戳

{% extends 'base.html' %}

{% block content %}
<h1>{% block title %}{{post['title']}}{%endblock%}</h1>
<span class="badge badge-primary">{{post['created']}}</span>

<p>{{post['content']}}</p>
{% endblock %}

新建博客并保存

在templates文件夹中修改new.html,修改blog.py:导入request、urlfor、flash、redirt,并在new()中加入对应功能,实现若为POST请求将请求体内容插入数据库中提交并重定向新Blog,加入网站密钥

from flask import Flask,render_template,request,url_for,flash,redirect
// ... existing code ...
app.config['SECRET_KEY'] ='sharing your flask,love is key'
// ... existing code ...
@app.route('/posts/new',methods=['GET','POST'])
def new():
    if request.method=='POST':
        title=request.form['title']
        content=request.form['content']
        if not title:
            flash('标题不可为空')
        elif not content:
            flash('内容不可为空')
        else:
            conn=get_db_conn()
            conn.execute('insert into posts(title,content) values (?,?)',(title,content))
            conn.commit()
            conn.close()
            flash('成功提交Blog')
            return redirect(url_for('index'))
    return render_template('new.html')
// ... existing code ...

##增加新建文章提示 在base.html的容器中加入遍历message提示flash的控制块

{% for message in get_flashed_messages() %}
<div class="alert alert-danger">{{message}}</div>
{% endfor %}

修改index的展示逻辑,变为order by created的按创造时间排序

// ... existing code ...
posts=conn.execute('select * from posts order by created DESC').fetchall()
// ... existing code ...

修改base,在指定列表中加入新建Blog链接

<li class="nav-item active">
    <a class="nav-link" href="{{url_for('new')}}">新建Blog</a>
</li>

编辑博客

在blog.py中加入编辑函数edit

@app.route('/posts/<int:post_id>/edit',methods=['GET','POST'])
def edit(post_id):
    post=get_post(post_id)
    if request.method=='POST':
        title=request.form['title']
        content=request.form['content']
        if not title:
            flash('标题不可为空')
        elif not content:
            flash('内容不可为空')
        else:
            conn=get_db_conn()
            conn.execute('update posts set title=?,content=? where id=?',(title,content,post_id))
            conn.commit()
            conn.close()
            flash('成功修改Blog')
            return redirect(url_for('index'))
    return render_template('edit.html',post=post)

在templates文件夹中新建edit.html,注意:编辑中的标题内容可能来自于post或request

{% extends 'base.html' %}

{% block content %}
<h1>{% block title %}编辑"{{post['title']}}"{% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="title">标题</label>
        <input type="text" class="form-control" id="title" name="title"
            value="{{ request.form['title'] or post['title'] }}">
        <!-- 这里尤其注意 -->
    </div>

    <div class="form-group">
        <label for="content">内容</label>
        <textarea class="form-control" placeholder="博客内容"
            name="content">{{ request.form['内容'] or post['content'] }}</textarea>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">提交</button>
    </div>
</form>
<hr>
{% endblock %}

删除博客

在blog.py中加入删除函数delete,注意使用POST方法而不用GET方法,防止爬虫删除数据

@app.route('/posts/<int:post_id>/delete',methods=['POST'])
def delete(post_id):
    post=get_post(post_id)
    conn=get_db_conn()
    conn.execute('delete from posts where id=?',(post_id,))
    conn.commit()
    conn.close()
    flash('成功删除Blog"{}"'.format(post['title']))
    return redirect(url_for('index')) 

修改post.html,加入删除按钮

<form action="{{ url_for('delete', id=post['id']) }}" method="POST">
    <input type="submit" value="删除" class="btn btn-danger btn-sm"
        onclick="return confirm('确定要删除吗?')">
</form>