为了账号安全,请及时绑定邮箱和手机立即绑定

用Neon Postgres构建可扩展的Flask应用

标签:
Python Flask

构建可扩展的 Web 应用需要周密的计划和正确的工具。Flask 是一个适合构建各种大小 Web 应用的 Python 框架。它提供了灵活性和扩展性,因此深受开发者欢迎。

本指南将带你了解如何开发一个使用Neon Postgres的Flask应用程序。我们将涵盖设置项目结构、定义模型和创建路由以及处理数据库迁移过程。我们还将探讨如何使用Tailwind CSS进行前端开发,以实现响应式设计。

先决条件
  • 已安装 Python 3.7 或更高版本

  • Node.js 18 或更高版本

  • 用于托管 Postgres 的 Neon 账户

  • 了解 Flask 和 SQLAlchemy 的基础知识
项目启动
  1. 创建一个新的目录并搭建一个虚拟环境
$ mkdir flask-neon-app
$ cd flask-neon-app
$ python -m venv venv
# 在 Windows 上,请使用 `venv\Scripts\activate` 命令激活环境。
$ source venv/bin/activate  # 请使用上述 Windows 命令

切换到全屏 退出全屏

  1. 安装所需的软件包。

在命令行中运行以下命令来安装这些Python包:

pip install flask flask-sqlalchemy psycopg2-binary python-dotenv flask-migrate

切换到全屏,退出全屏

创建一个requirements.txt文件用于包管理。

pip freeze > requirements.txt

将当前环境中已安装的包列表导出到requirements.txt文件中

全屏播放,退出全屏

这个文件会帮助你管理依赖关系,并确保开发和部署环境的一致。

  1. 创建一个用于存放环境配置的 .env 文件。
DATABASE_URL=postgresql://user:password@your-neon-host:5432/your-database

进入全屏/退出全屏

用您的userpasswordyour-neon-hostyour-database替换这些字段。

应用程序结构

对于小型应用,你可以将所有代码放在一个文件里。但是,随着应用变大,最好将代码拆分成单独的模块。将模型、路由、服务和工具分别放在不同的目录里是一个良好的实践做法来说。

一个典型的 Flask 应用结构可能如下:

flask-neon-app/
├── app/
│   ├── __init__.py
│   │   # 初始化文件,包含应用的设置和配置
│   ├── models/
│   │   # 存储数据模型定义的目录
│   ├── routes/
│   │   # 定义应用路由的目录
│   ├── services/
│   │   # 应用服务实现的目录
│   ├── static/
│   │   ├── css/
│   │       # 存放CSS文件的目录
│   ├── templates/
│   │   # 存放HTML模板文件的目录
│   └── utils/
│       # 存放工具函数和辅助代码的目录
├── config.py
│   # 应用配置文件
├── requirements.txt
│   # 列出项目依赖的文件
├── run.py
│   # 运行应用的入口文件
└── tailwind.config.js
    # Tailwind CSS 的配置文件

全屏模式,退出全屏

这种结构分离了关注点,让应用程序更容易维护和扩展。app 目录包含了核心应用逻辑,其他文件和目录则分别负责配置、依赖和前端资源。

数据库设置

可以将 app/__init__.py 文件视为 Flask 应用的入口点。它初始化 Flask 应用实例,设置数据库连接并初始化,并注册蓝图来处理路由。

通过添加 __init__.py 文件,你可以将 app 目录变成一个 Python 包。这样你就可以在其他文件中导入 app 包里的模块了。

app 是 Flask 应用程序中常用的目录名称,但根据你的项目需求,如果你更喜欢,也可以选择其他名称。

考虑到这一点,我们设置数据库连接并初始化Flask应用实例。在app/__init__.py中添加如下代码:

    从 flask 导入 Flask
    从 flask_sqlalchemy 导入 SQLAlchemy
    从 flask_migrate 导入 Migrate
    从 dotenv 导入 load_dotenv()

    load_dotenv()

    db = SQLAlchemy()
    migrate = Migrate()

    def create_app():
        app = Flask(__name__)
        app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL')
        app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

        db.init_app(app)
        migrate.init_app(app, db)

        # 在这里注册蓝图
        从 app.routes 导入 user_routes
        app.register_blueprint(user_routes.user_bp)

        return app

切换到全屏模式,退出全屏

这个配置初始化了Flask、SQLAlchemy和Flask-Migrate。它从环境变量中加载数据库URL,并禁用了SQLAlchemy的修改追踪功能以提高性能。

蓝图是组织 Flask 应用中相关路由和视图的工具。蓝图可以帮助我们在 Flask 应用中更好地组织相关的路由和视图。我们将在下一节介绍蓝图和路由。

要了解更多关于Flask-Migrate的内容,请查阅使用Flask和Neon Postgres进行数据库迁移和模式变更的指南

定义模型

在 web 应用中,实体代表你的数据库中的数据结构及其关系。在 Flask 和 SQLAlchemy 的上下文中来说,实体是 Python 类,这些类映射到数据库表,并使你可以定义表的结构以及表之间的关系。

以下是一个典型的模型定义的例子,让我们在 app/models/user.py 文件中定义一个 User 模型:

    from app import db
    from datetime import datetime

    class User(db.Model):
        # 用户模型类
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True, nullable=False)
        email = db.Column(db.String(120), unique=True, nullable=False)
        created_at = db.Column(db.DateTime, default=datetime.utcnow)

        def __repr__(self):
            # 返回用户名的字符串表示
            return f'<User {self.username}>'

        def to_dict(self):
            # 将用户对象转换为字典
            return {
                'id': self.id,
                'username': self.username,
                'email': self.email,
                'created_at': self.created_at.isoformat()
            }

进入全屏 退出全屏

此模型定义了一个用户对象,包括 usernameemailcreated_at 这些字段。__repr__ 方法提供模型实例的字符串表示,方便调试和日志记录。to_dict 方法便于将模型转换为 JSON 格式,这在 API 返回数据时非常有用。

使用蓝图创建路线

在 Flask 中,蓝图是组织应用程序组件的一种好方法。它们允许你将相关的路由、视图函数、模板和静态文件分组,帮助你更好地结构化大型应用并分离不同功能区域。

如果你熟悉 Laravel,那么 Flask 中的蓝图就像 Laravel 中的控制器和路由组,可以让你逻辑地组织和划分路由及其相关功能和逻辑。

在Flask中使用蓝图(blueprints)的主要好处包括将相关的路由分组,将应用程序组织成模块化的组件,以及避免命名冲突在应用程序的不同部分之间发生。

这里是一个在名为 Flask 的应用中使用蓝图的扩展示例,用于处理用户相关路由的文件,如下所示:
文件名为 app/routes/user_routes.py

    from flask import Blueprint, jsonify, request, render_template, redirect, url_for
    from app.models.user import User
    from app import db

    # 创建一个名为 'user' 的蓝图(Blueprint),并设置 URL 前缀为 '/user'
    user_bp = Blueprint('user', __name__, url_prefix='/user')

    # 路由,用于创建新用户(HTML表单提交)
    @user_bp.route('/create', methods=['POST'])
    def create_user():
        data = request.form
        new_user = User(username=data['username'], email=data['email'])
        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('user.list_users'))

    # 路由,用于显示所有用户(HTML)
    @user_bp.route('/list', methods=['GET'])
    def list_users():
        users = User.query.all()
        return render_template('users.html', users=users)

    # API 路由,用于获取所有用户(JSON)
    @user_bp.route('/api/list', methods=['GET'])
    def get_users_api():
        users = User.query.all()
        return jsonify([user.to_dict() for user in users])

    # 路由,用于显示单个用户(HTML)
    @user_bp.route('/<int:user_id>', methods=['GET'])
    def get_user(user_id):
        user = User.query.get_or_404(user_id)
        return render_template('user_detail.html', user=user)

    # API 路由,用于获取单个用户(JSON)
    @user_bp.route('/api/<int:user_id>', methods=['GET'])
    def get_user_api(user_id):
        user = User.query.get_or_404(user_id)
        return jsonify(user.to_dict())

全屏显示 退出全屏

我们来分析这段代码:

  1. 我们导入必要的模块并创建一个名为 'user' 的蓝图,并带有 URL 前缀 '/user'。此前缀会被添加到该蓝图中定义的所有路由前面,有助于将路由组织成逻辑分组。如果你有多个蓝图,每个都可以有自己的 URL 前缀,这样更方便管理和区分。

  2. create_user(): 此路由处理 POST 请求来创建新用户。它读取表单数据,创建一个 User 实例,将其添加到数据库会话并提交事务。然后重定向到 list_users() 路由页面。

    list_users(): 列出用户。此路由以HTML格式展示所有用户信息。它从数据库中查询所有用户数据并渲染包含这些数据的模板。

  3. get_users_api():此 API 路由返回所有用户的 JSON 格式信息。它从数据库中查询所有用户并将他们转换为字典,使用 to_dict() 方法,并返回一个 JSON 格式的响应。

  4. get_user(): 这个路由会用 HTML 格式展示一个用户的详细信息。它通过 ID 来查找用户,如果找不到用户就返回一个 404 错误信息。

  5. get_user_api():此 API 路由返回一个用户的详情,以 JSON 格式。它通过 ID 来获取用户信息,若用户不存在,则返回 404 错误。

要在您的主Flask应用中启用此蓝图,您可以在之前看到的app/__init__.py文件中像这样注册它。

    从 flask 模块导入 Flask 类
    从 app.routes.user_routes 模块导入 user_bp

    创建一个 Flask 应用实例 app
    app.register_blueprint(user_bp)

进入全屏 / 退出全屏

这种结构让你可以把相关的路由放在一起,这让你的应用程序更加模块化,也更容易维护,随着应用的发展。

基于 Tailwind CSS 和模版的前端开发

Tailwind CSS 是一个实用优先的 CSS 框架,帮助您快速创建自定义用户界面。它提供低级实用类,让您无需离开 HTML 就可以构建完全个性化的设计。

要将 Tailwind CSS 与 Flask 模板集成,您可以按以下步骤来做,以下步骤,确保在中文中更流畅自然。

  1. 安装 Tailwind CSS 插件。
首先运行这个命令来初始化npm项目
npm init -y
然后安装Tailwind CSS库
npm install tailwindcss
最后使用npx来初始化Tailwind配置文件
npx tailwindcss init

全屏模式 退出全屏

这初始化了一个新的Node.js项目,安装Tailwind CSS,并创建一个基本的Tailwind配置。

  1. 更新 tailwind.config.js 配置文件,添加您的 HTML 模板
       module.exports = {
         content: ['./app/templates/**/*.html'],
         theme: {
           extend: {},
         },
         plugins: [],
       };

这段代码导出了一个配置对象,其中content字段指定了HTML文件的路径,theme字段定义了主题扩展,而plugins字段为空,表示没有使用任何插件。

全屏模式 退出全屏模式

此配置让Tailwind扫描您的HTML模板,找出要包含在最终CSS输出里的类。extend键则可以让您自定义Tailwind的初始主题。

创建一个 app/static/css/main.css 文件:

       @tailwind 基本样式;
       @tailwind 组件样式;
       @tailwind 工具类;

全屏 退出全屏

此文件导入了 Tailwind 的基本样式、组件类样式和实用类。它作为 Tailwind 引入样式的入口。

  1. 编译, Tailwind CSS 代码:

你可以使用以下命令来运行 Tailwind CSS 的 watch 模式:

npx tailwindcss -i ./app/static/css/main.css -o ./app/static/css/output.css --watch

点这里进入全屏 点这里退出全屏

这条命令会编译你的 Tailwind CSS 文件并监视文件中的变化。这使你可以通过只在模板中包含实际使用的样式来保持 CSS 文件尽可能小,这对于性能优化非常重要,因为随着应用程序的增长,过多的无用样式会拖慢你的网站速度。

--watch 参数确保当你修改 HTML 文件时会自动重新编译 CSS,这在快速开发和实时重载时非常有帮助。

  1. app/templates/ 目录下的 base.html 文件中新建一个基础模版。
       <!doctype html>
       <html lang="en">
         <head>
           <meta charset="UTF-8" />
           <meta name="viewport" content="width=device-width, initial-scale=1.0" />
           <title>{% block title %}Flask 霓虹应用{% endblock %}</title>
           <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}" />
         </head>
         <body class="bg-gray-100">
           <nav class="bg-blue-500 p-4 text-white">
             <div class="container mx-auto">
               <a href="/" class="text-2xl font-bold">Flask 霓虹应用</a>
             </div>
           </nav>
           <main class="container mx-auto mt-8">{% block content %}{% endblock %}</main>
         </body>
       </html>

进入全屏 退出全屏

此基础模板定义了您的HTML页面的基本结构如下。它包含以下内容:

  • 可被子模板覆盖的标题块
  • 链接到编译后的Tailwind CSS文件
  • 一个使用Tailwind类样式的简单导航栏
  • 主内容区,子模板可以通过Jinja2模板继承来填充此区域

    1。创建一个 app/templates/users.html 文件。

       {% extends "base.html" %} {% block title %}用户{% endblock %} {% block content %}
       <h1 class="mb-4 text-3xl font-bold">用户</h1>
       <div class="rounded bg-white p-4 shadow-md">
         <form action="{{ url_for('user.create_user') }}" method="post" class="mb-4">
           <input type="text" name="username" placeholder="昵称" required class="mr-2 border p-2" />
           <input type="email" name="email" placeholder="邮箱" required class="mr-2 border p-2" />
           <button type="submit" class="bg-blue-500 rounded px-4 py-2 text-white">添加新用户</button>
         </form>
         <ul>
           {% for user in users %}
           <li class="mb-2">会员:{{ user.email }}</li>
           {% endfor %}
         </ul>
       </div>
       {% endblock %}

切换到全屏 退出全屏

此模板使用{% extends "base.html" %}扩展了基础模板文件,并为用户页面提供了具体的内容。它包含以下内容:

  • 一个用于添加新用户的表单,使用 Tailwind 类样式
  • 一个现有的用户列表,同样使用 Tailwind 类样式
  • 用于动态内容的 Jinja2 模板语法,例如 {% for user in users %}

Tailwind CSS 和 Jinja2 模板技术让你可以灵活地设计前端,同时保持代码的整洁和易于维护。这种方法让你能轻松构建响应式且视觉效果出色的 web 应用。

数据库迁移

数据库迁移是管理应用程序数据库模式随时间变化的重要手段。它们允许您逐步调整数据库结构,使其与应用程序模型同步。我们将使用 Flask-Migrate,这是一个为 Flask 设计的扩展,使用 Alembic 来处理 SQLAlchemy 的数据库迁移,使此过程变得简单。

这里有一份快速指南,教你如何设置和使用Flask-Migrate来管理数据库版本更新。

  1. 开始迁移仓库初始化。
flask db init

在一个 Flask 应用中初始化数据库的命令。

全屏模式退出全屏

此命令用于创建一个新的迁移仓库目录,并在该目录中创建处理迁移所需的文件。

  1. 新建一个迁移文件:
flask db migrate -m "初始迁移指令" # 初始迁移

按F11全屏/退出全屏

这个命令根据检测到的模型变化创建一个新的迁移脚本。与其他一些迁移工具不同,Flask-Migrate 自动检测你的模型变化并生成迁移脚本,不需要你手动编写。然而,建议你总是检查生成的迁移脚本以确保它准确反映了你预期的变化。

你可以使用 -m 标志来提供迁移的简短描述,这有助于我们追踪随着时间变化的情况。

  1. 执行迁移:
执行 `flask db upgrade` 命令

全屏模式:进入,退出

该命令会将迁移应用到您的数据库,进行必要的模式变更。

在应用迁移脚本之前,先检查生成的迁移脚本是很重要的,尤其是在生产环境中。虽然 Flask-Migrate 通常能很好地检测变化,但复杂的修改可能需要手动调整迁移脚本的内容。

对于更高级的使用方法,Flask-Migrate 提供了一些额外的命令。

  • flask db downgrade:回退最后一次迁移
  • flask db current:显示当前数据库版本号
  • flask db history:显示迁移历史记录

你应该将迁移文件提交到版本控制,这样所有开发人员和部署环境就可以保持数据库结构的一致性。

要了解更多关于使用 Flask 和 Neon Postgres 管理数据库迁移的信息,请参阅这篇文章《使用 Flask 和 Neon Postgres 管理数据库迁移》指南。

可扩展性的考量

除了上述步骤外,随着您的Flask应用程序的发展,您可以考虑一些策略来提高性能和增强可扩展性。这里有一些最佳实践供您参考。

  1. 连接池是一种高效管理数据库连接的技术。连接池保持了一组可以重复使用的连接,而是为每个数据库操作保持一组可用连接,避免频繁打开和关闭新的连接。

Neon PostgreSQL 支持连接池功能,通过减少创建新连接的开销,可以大大提升应用表现。

当使用Neon的连接池时:

       # 将你的 DATABASE_URL 更新为连接池字符串(即数据库URL)
       app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@pooler.address:5432/database'

切换到全屏 切换回正常模式

参阅Neon文档中的连接池相关文档以获取更多信息。

  1. 为了优化性能,考虑缓存经常访问的数据。缓存可以减轻数据库的负担并加快用户响应速度。

使用 Flask-Caching 来缓存频繁访问的信息。

       从flask_caching导入Cache

       cache = Cache()  # 创建一个缓存实例

       def create_app():
           # ... 之前的代码 ...
           cache.init_app(app, config={'CACHE_TYPE': 'simple'})

           return app

       @user_bp.route('/api/users', methods=['GET'])
       @cache.cached(timeout=60)  # 缓存 函数结果 60 秒
       def get_users_api():
           users = User.query.all()
           return jsonify([user.to_dict() for user in users])

全屏模式 退出全屏

这个示例使用的是简单的内存缓存。在生产环境中,您可以切换到类似 Redis 的缓存后端。

  1. 异步处理可以让你的应用程序在不阻塞主请求响应循环的情况下处理那些耗时的任务。您可以利用 Celery(一个分布式任务队列)异步执行后台任务。

要将Celery与Flask集成在一起,你需要安装celery包,并在你的Flask应用中进行配置设置:

在命令行中运行如下命令:

       pip install celery

全屏 退出全屏

       导入 Celery 作为 celery

       celery = Celery(__name__)

       # 定义 create_app 函数
       def create_app():
           # ... 更早的代码 ...
           celery.conf.update(app.config)

           return app

       @celery.task
       def send_email(user_id):
           # 用户查询获取用户ID
           user = User.query.get(user_id)
           # 发送邮件给用户

       # 调用 send_email 任务异步执行
       send_email.delay(user_id)

切换到全屏 退出全屏

下面的例子定义了一个Celery任务来异步发送电子邮件给用户。你可以运行Celery工作者来在后台异步处理这些任务。

  1. 速率限制有助于防止您的API被滥用并保障使用公平,是保护公共API的重要安全措施。

使用 Flask-Limiter 实现速率限制:

       从 flask_limiter 导入 Limiter
       从 flask_limiter.util 导入 get_remote_address

       limiter = Limiter(key_func=get_remote_address)

       def 创建应用():
           # ... 之前的代码 ... (省略)
           limiter.init_app(app)

           返回 app

       @user_bp.route('/api/users', methods=['GET'])
       @limiter.limit("5 per minute")
       def 获取用户():
           用户 = User.query.all()
           返回 转JSON([user.to_dict() for user in 用户])

进入全屏 退出全屏

这个示例将 /api/users API 端点的访问限制为每分钟每个 IP 地址只能有 5 次请求。您可以根据您的应用程序需求和资源情况来调整这个限制。

结论

通过遵循这些实践,您已经搭建了一个可扩展的Flask应用,使用了Neon Postgres数据库,并且前端采用了Tailwind CSS。这种架构让您的项目更容易扩展和维护。

作为下一步,考虑为您的应用程序添加认证、授权访问和错误处理机制。这些功能对于确保您的应用程序的安全性和提供良好的用户体验和流畅的操作感受至关重要。

你也应该考虑测试你的应用程序,以确保其可靠性和良好的性能。单元测试、集成测试和端到端测试(E2E测试)可以帮助你尽早发现错误并保持代码的质量。使用Neon的分支特性来测试你的应用程序,这可以帮助你在将新功能部署到生产环境之前单独进行测试。

更多资源
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消