一文搞定Python中的flask库基础与实例:开发一个完整的博客Web

目录

1. 前言

2. Flask 基本概念

3. Flask 适应场景

4. Flask 实操:个人博客系统

4.1 项目结构

 4.2 app.py

 4.3 模板文件兼主页(base.html)

4.4 我的博客列表:index.html

4.5 文章详细页:post.html

4.6 登录页:login.html

4.7 新建博客页:create.html

4.8 CSS样式

5. 总结


1. 前言

在众多的 Python Web 开发框架中,Flask 像一颗闪耀的明星,备受开发者的青睐。无论是小型的个人项目,还是大型的商业应用,Flask 都能展现出其独特的优势和魅力。作为一名 Python 开发者,深入学习和掌握 Flask 库是提升开发技能、拓展项目选择范围的关键一步。本文将带大家全面了解 Flask,从它的基本概念、适应场景,到实际代码示例,助大家搭建自己的UI界面和Web。

因为本片文件搭建了一个完整的博客网站实例,所以需要有HTML知识、CSS知识及JS知识,可以去阅读:

《一文全面解析HTML网页》

《一文看懂网页开发中的CSS(Cascading Style Sheets,层叠样式表)》

《一文看懂网页开发中的JavaScript:使网页能交互》 

2. Flask 基本概念

Flask 是一个用 Python 编写的轻量级 Web 应用框架。它基于 Werkzeug WSGI 工具箱和 Jinja2 模板引擎。所谓轻量级,意味着 Flask 核心功能简洁,没有许多大型框架那样复杂的默认配置和模块依赖,这使得开发者可以根据项目需求灵活地扩展和定制功能。

其中核心组件如下:

应用实例(app) :是 Flask 应用的核心。通过创建 Flask 类的实例来启动应用。例如:

from flask import Flask
app = Flask(__name__)

__name__ 表示当前模块的名称,Flask 使用它来确定应用的根目录,以便正确地处理静态文件、模板等资源。 

路由(Route) :用于将 URL 映射到对应的处理函数。例如:

@app.route('/')
def home():
    return 'Hello, Flask!'

当用户访问网站的根 URL(即 “/”)时,Flask 会调用 home 函数,并返回字符串 “Hello, Flask!” 作为响应。

视图函数(View Function) :与路由关联的函数,负责处理客户端请求并返回响应。如上述的 home 函数就是视图函数。

模板(Template) :用于分离 Python 代码和 HTML 页面,使页面更具可读性和可维护性。Flask 默认使用 Jinja2 模板引擎。例如,在 templates 文件夹下创建一个 index.html 模板文件:

<!DOCTYPE html>
<html>
<head>
    <title>Flask 模板示例</title>
</head>
<body>
    <h1>{{ message }}</h1>
</body>
</html>

在视图函数中可以通过 render_template 函数将变量传递给模板并渲染:

from flask import render_template

@app.route('/template')
def template_demo():
    return render_template('index.html', message='Hello, Template!')

访问 “/template” URL 时,页面会显示 “Hello, Template!”。

其中render_template(template_name, **context)将模板文件中的动态内容与实际数据结合,生成最终的 HTML 页面:

  • template_name :这是一个字符串,表示要渲染的模板文件的名称。Flask 会自动在应用的 templates 文件夹中查找这个模板文件。

  • context :这是一个关键字参数列表,用于将变量传递给模板。这些变量可以在模板中使用,以便生成动态内容。例如,render_template('index.html', name='John') 会将变量 name 的值设置为 'John',然后在模板中可以通过 {{ name }} 来引用这个变量。

请求对象(Request Object) :用于获取客户端请求的数据,如表单数据、查询参数等。例如:

from flask import request

@app.route('/form', methods=['POST'])
def form_example():
    name = request.form['name']
    return f'Hello, {name}!'

@app.route('/query')
def query_example():
    name = request.args.get('name', 'Guest')
    return f'Hello, {name}!'

当以 POST 方法提交表单到 “/form” URL 时,可以从 request.form 中获取表单字段 “name” 的值;访问 “/query?name=John” URL 时,可以从 request.args 中获取查询参数 “name” 的值。

3. Flask 适应场景

  • 小型网站和应用 :Flask 的轻量级特性使其非常适合快速开发小型网站,如个人博客、简历网站、小工具应用等。不需要复杂的配置和大量依赖,开发者可以迅速搭建起基本的 Web 功能。

  • 原型开发和 MVP(最小可行产品)测试 :对于初创团队或新项目,在开发初期需要快速验证产品概念和用户需求时,Flask 能够以较少的代码和开发时间构建出可运行的原型系统,方便展示给用户和投资者进行反馈收集。

  • 微服务架构中的服务 :在构建微服务系统时,Flask 作为一个独立的服务组件,易于与其他服务进行集成和通信。其简洁的结构便于实现特定的业务功能,并且可以方便地进行扩展和维护。

  • API 服务 :可以使用 Flask 构建 RESTful API 服务,为前端应用或其他系统提供数据接口。通过定义路由和视图函数来处理不同的 HTTP 请求方法(如 GET、POST、PUT、DELETE 等),返回 JSON 格式的数据响应。

4. Flask 实操:个人博客系统

下面将以一个简单的博客系统为例,展示 Flask 的实际应用。

4.1 项目结构

my-blog/
├── app.py
├── data/
│   └── posts.json
├── templates/
│   ├── base.html
│   ├── index.html
│   ├── post.html
│   ├── login.html
│   └── create.html
└── static/
    └── css/
        └── style.css

 4.2 app.py

from flask import Flask, render_template, request, redirect, url_for, jsonify, session
import json
import os

app = Flask(__name__)
app.secret_key = 'your-secret-key-123'  # 生产环境中应使用更复杂的密钥


def load_posts():
    try:
        with open('data/posts.json', 'r') as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return []


def save_posts(posts):
    os.makedirs('data', exist_ok=True)
    with open('data/posts.json', 'w') as f:
        json.dump(posts, f, indent=4)


@app.route('/')
def index():
    posts = load_posts()
    return render_template('base.html', posts=posts)


@app.route('/mypostlist')
def mypostlist():
    posts = load_posts()
    return render_template('index.html', posts=posts)


@app.route('/post/<int:post_id>')
def post(post_id):
    posts = load_posts()
    post = next((p for p in posts if p['id'] == post_id), None)
    return render_template('post.html', post=post) if post else ('Post not found', 404)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        if request.form['username'] == 'admin' and request.form['password'] == 'secret':
            session['logged_in'] = True
            return redirect(url_for('index'))
        return 'Invalid credentials', 401
    return render_template('login.html')


@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    return redirect(url_for('index'))


@app.route('/create')
def create_post():
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    return render_template('create.html')


@app.route('/api/add_post', methods=['POST'])
def api_add_post():
    if not session.get('logged_in'):
        return jsonify({'error': 'Unauthorized'}), 401

    data = request.get_json()
    if not (data.get('title') and data.get('content')):
        return jsonify({'error': 'Missing title or content'}), 400

    posts = load_posts()
    new_post = {
        'id': len(posts) + 1,
        'title': data['title'],
        'content': data['content']
    }
    posts.append(new_post)
    save_posts(posts)
    return jsonify(new_post), 201


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

 4.3 模板文件兼主页(base.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Blog - {% block title %}{% endblock %}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">Home</a>
        {% if session.logged_in %}
            <a href="{{ url_for('create_post') }}">New Post</a>
            <a href="{{ url_for('logout') }}">Logout</a>
            <a href="{{ url_for('mypostlist') }}">my-post</a>
        {% else %}
            <a href="{{ url_for('login') }}">Login</a>
        {% endif %}
    </nav>
    <div class="container">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

4.4 我的博客列表:index.html

{% extends "base.html" %}

{% block title %}Home{% endblock %}

{% block content %}
    <h1>Latest Posts</h1>
    {% for post in posts %}
        <article class="post">
            <h2><a href="{{ url_for('post', post_id=post.id) }}">{{ post.title }}</a></h2>
            <p>{{ post.content[:150] }}{% if post.content|length > 150 %}...{% endif %}</p>
        </article>
    {% endfor %}
    <a href="{{ url_for('index') }}">← Back to base</a>
{% endblock %}

4.5 文章详细页:post.html

{% extends "base.html" %}

{% block title %}{{ post.title }}{% endblock %}

{% block content %}
    <article class="post-detail">
        <h1>{{ post.title }}</h1>
        <p>{{ post.content }}</p>
        <a href="{{ url_for('mypostlist') }}">← Back to all posts</a>
    </article>
{% endblock %}

4.6 登录页:login.html

{% extends "base.html" %}

{% block title %}Login{% endblock %}

{% block content %}
    <h1>Login</h1>
    <form method="POST">
        <div class="form-group">
            <label for="username">Username:</label>
            <input type="text" id="username" name="username" required>
        </div>
        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" id="password" name="password" required>
        </div>
        <button type="submit">Login</button>
    </form>
{% endblock %}

4.7 新建博客页:create.html

{% extends "base.html" %}

{% block title %}New Post{% endblock %}

{% block content %}
    <h1>Create New Post</h1>
    <form id="new-post-form">
        <div class="form-group">
            <label for="title">Title:</label>
            <input type="text" id="title" name="title" required>
        </div>
        <div class="form-group">
            <label for="content">Content:</label>
            <textarea id="content" name="content" rows="6" required></textarea>
        </div>
        <button type="submit">Publish</button>
    </form>

    <script>
        document.getElementById('new-post-form').addEventListener('submit', async (e) => {
            e.preventDefault();
            
            const response = await fetch('/api/add_post', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    title: document.getElementById('title').value,
                    content: document.getElementById('content').value
                })
            });

            if (response.ok) {
                window.location.href = '/';
            } else {
                alert('Error creating post');
            }
        });
    </script>
{% endblock %}

4.8 CSS样式

/* Basic reset */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    color: #333;
    background-color: #f9f9f9;
}

nav {
    background: #333;
    padding: 1rem;
}

nav a {
    color: white;
    text-decoration: none;
    margin-right: 1.5rem;
}

nav a:hover {
    text-decoration: underline;
}

.container {
    max-width: 800px;
    margin: 2rem auto;
    padding: 0 1rem;
}

.post {
    background: white;
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.post h2 {
    margin-bottom: 0.5rem;
    color: #222;
}

.post p {
    color: #666;
}

.form-group {
    margin-bottom: 1rem;
}

input, textarea {
    width: 100%;
    padding: 0.5rem;
    margin-top: 0.25rem;
    border: 1px solid #ddd;
    border-radius: 4px;
}

button {
    background: #333;
    color: white;
    padding: 0.5rem 1rem;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background: #555;
}

.post-detail {
    background: white;
    padding: 2rem;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.post-detail h1 {
    margin-bottom: 1rem;
}

 最后,在命令行中,进入项目目录,运行以下命令启动 Flask 应用:

python app.py

然后在浏览器中访问 “http://127.0.0.1:5000/” 即可查看博客首页,访问 “http://127.0.0.1:5000/login” 可以尝试登录(用户名为 “admin”,密码为 “secret”),登录成功后在新建博客页通过发送 POST 请求到 “http://127.0.0.1:5000/api/add_post” 可以添加新的博客文章,提交后保存到data文件中,通过mypostlist逐个查询访问具体博客。

5. 总结

Flask 以其简洁、灵活的特点在 Python Web 开发领域占据重要地位。它不仅为开发者提供了快速构建 Web 应用的能力,还通过丰富的扩展插件满足各种复杂功能需求。无论是小型项目还是大型系统,Flask 都能大显身手。通过对 Flask 基本概念的理解、适应场景的把握以及实际案例的操作,你已经迈出了成为熟练 Flask 开发者的坚实步伐。在后续的学习和实践中,不断探索 Flask 的更多功能和优化技巧,相信你将能够开发出更加出色的 Web 应用。我是橙色小博,关注我,一起在人工智能领域学习进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

橙色小博

一起在人工智能领域学习进步!

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

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

打赏作者

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

抵扣说明:

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

余额充值