FLASK 框架 (关于Flask框架的简单学习和项目实战)
🤟致敬读者
- 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉
📘博主相关
- 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息
文章目录
- FLASK 框架 (关于Flask框架的简单学习和项目实战)
- 1. Flask入门介绍
- 1.1 概括
- 1.2 核心特点
- 1.3 代码实例
- 1.4 主要组成部分
- 1.5 适用场景
- 1.6 不适用场景
- 1.7 总结
- 2. 引入库(可跳过)
- 3. demo实例(任务管理应用)
- 3.1 项目结构预览
- 3.2 配置文件
- 3.3 应用初始化
- 3.4 数据模型
- 3.5 路由和视图
- 3.6 基础模板
- 3.7 主页模板
- 3.8 登录模板
- 3.9 注册模板
- 3.10 任务管理模板
- 3.11 样式文件
- 3.12 运行文件
- 3.13 依赖文件
- 4. 数据库创建
- 4.1 数据库登录
- 4.2 创建数据库和用户
- 4.3 连接数据库
- 5. 安装依赖
- 6. 运行程序
- 7. 访问
- 8. 注意事项
📃文章前言
- 🔷文章均为学习工作中整理的笔记。
- 🔶如有错误请指正,共同学习进步。
FLASK 框架 (关于Flask框架的简单学习和项目实战)
1. Flask入门介绍
1.1 概括
Flask 是一个用 Python 编写的轻量级 Web 应用框架。它非常小巧灵活,被称为“微框架”,但可以通过扩展来增加各种强大功能。
1.2 核心特点
- 轻量且简单:核心功能非常精简,没有默认使用的数据库、表单验证等组件。这让你可以自由选择最适合项目的工具,学习曲线平缓。
- 灵活自由:它不像一些“大而全”的框架(如 Django)有很强的约束和固定的项目结构。你可以按自己喜欢的方式组织代码,构建各种类型的应用,从简单的静态页面到复杂的 API 服务。
- 易于上手:只需几行代码就能快速启动一个 Web 服务器,看到效果,对新手非常友好。
- 强大的扩展生态:虽然核心简单,但社区提供了大量官方和第三方的扩展,可以像搭积木一样轻松地添加数据库集成、用户认证、表单处理、邮件发送等功能。
1.3 代码实例
一个最简单的 Flask 应用
下面这个例子展示了 Flask 的核心魅力:简洁。
# 导入 Flask 类
from flask import Flask# 创建 Flask 应用实例
app = Flask(__name__)# 定义路由和视图函数
@app.route('/')
def hello_world():return 'Hello, World!'# 运行应用
if __name__ == '__main__':app.run(debug=True)
解释一下这几行代码:
app = Flask(__name__)
:创建一个 Flask 应用对象。@app.route('/')
:这是一个装饰器。它告诉 Flask,当用户访问网站的根路径(即主页www.yoursite.com/
)时,应该执行哪个函数。def hello_world():
:这就是视图函数。它处理请求并返回显示给用户的内容(这里返回一个简单的字符串)。app.run(debug=True)
:启动内置的开发服务器。debug=True
表示开启调试模式,代码修改后服务器会自动重启,方便开发。
将上面的代码保存为 app.py
,然后在命令行运行 python app.py
,你就拥有了一个运行在 http://127.0.0.1:5000/
的网站!访问它,你就会看到 Hello, World!
。
1.4 主要组成部分
- 路由:将不同的 URL 映射到对应的处理函数上(例如,
/users
对应显示用户列表的函数)。 - 视图函数:处理请求并返回响应(可以是 HTML 网页、JSON 数据、重定向等)的函数。
- Jinja2 模板引擎:Flask 内置的模板系统,可以让你在 HTML 中嵌入 Python 变量和逻辑,动态生成网页内容。
- 请求和响应对象:方便地处理用户发来的数据(如表单数据)和构建返回给用户的响应。
1.5 适用场景
- 快速开发小型项目或原型:想法可以迅速落地。
- 构建 RESTful API 服务:作为后端,为移动应用或前端框架(如 React, Vue)提供数据接口。这是 Flask 非常流行的用途。
- 微服务架构:每个小服务都可以用一个轻量级的 Flask 应用来构建。
- 学习 Web 开发:因为其简洁性,你可以清楚地理解 Web 框架的底层原理(如路由、请求/响应循环)。
1.6 不适用场景
- 超大型、复杂的项目:过多的自由度和灵活性在大型项目中可能反而成为劣势,导致结构混乱。这种情况下,约定优于配置的 Django 可能更合适。
- 需要“开箱即用”全套功能:如果你希望框架自带后台管理、用户认证、ORM 等所有功能,那 Flask 需要你花时间选择和集成扩展,而 Django 则直接提供了这些。
1.7 总结
Flask 就像一个工具箱,而不是一个成品家具。它给你提供了最基础、最核心的工具(路由、模板等),然后让你根据自己的具体需求,自由地挑选和组合其他工具(扩展)来建造你想要的东西。
对于想要灵活、可控且快速入门 Python Web 开发的开发者来说,Flask 是一个绝佳的选择。
2. 引入库(可跳过)
正常python中库的引入,使用pip命令下载然后import引入
本项目实战需引入不止一个,可将库的列表存放在一个txt文件中,项目启动前使用命令下载所有库
该部分放在后面的依赖安装章节中
3. demo实例(任务管理应用)
3.1 项目结构预览
提前规划项目结构,创建相关包和文件
创建项目目录flask_task_manager
flask_task_manager/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── index.html
│ │ ├── login.html
│ │ ├── register.html
│ │ └── tasks.html
│ └── static/
│ └── style.css
├── config.py
├── requirements.txt
└── run.py
3.2 配置文件
config.py
直接配置MySQL连接信息
import os
from datetime import timedeltabasedir = os.path.abspath(os.path.dirname(__file__))class Config:SECRET_KEY = os.environ.get('SECRET_KEY') or 'your-secret-key-here'# MySQL 数据库配置 - 直接设置MYSQL_HOST = 'localhost'MYSQL_USER = 'flask_user'MYSQL_PASSWORD = 'your_password'MYSQL_DB = 'flask_task_manager'MYSQL_PORT = 3306# 构建 SQLAlchemy 连接 URISQLALCHEMY_DATABASE_URI = f'mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DB}'SQLALCHEMY_TRACK_MODIFICATIONS = FalsePERMANENT_SESSION_LIFETIME = timedelta(days=7)# 可选:设置连接池大小SQLALCHEMY_ENGINE_OPTIONS = {'pool_size': 10,'pool_recycle': 300,'pool_pre_ping': True}class DevelopmentConfig(Config):DEBUG = Trueclass ProductionConfig(Config):DEBUG = False# 在生产环境中,应该使用环境变量MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')MYSQL_USER = os.environ.get('MYSQL_USER', 'flask_user')MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', '')MYSQL_DB = os.environ.get('MYSQL_DB', 'flask_task_manager')MYSQL_PORT = int(os.environ.get('MYSQL_PORT', 3306))SQLALCHEMY_DATABASE_URI = f'mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DB}'config = {'development': DevelopmentConfig,'production': ProductionConfig,'default': DevelopmentConfig
}
也可以使用环境变量读取参数配置
import os
from datetime import timedeltabasedir = os.path.abspath(os.path.dirname(__file__))class Config:SECRET_KEY = os.environ.get('SECRET_KEY') or 'your-secret-key-here'# MySQL 数据库配置MYSQL_HOST = os.environ.get('MYSQL_HOST') or 'localhost'MYSQL_USER = os.environ.get('MYSQL_USER') or 'your_mysql_username'MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD') or 'your_mysql_password'MYSQL_DB = os.environ.get('MYSQL_DB') or 'flask_task_manager'MYSQL_PORT = int(os.environ.get('MYSQL_PORT') or 3306)# 构建 SQLAlchemy 连接 URISQLALCHEMY_DATABASE_URI = f'mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DB}'SQLALCHEMY_TRACK_MODIFICATIONS = FalsePERMANENT_SESSION_LIFETIME = timedelta(days=7)# 可选:设置连接池大小SQLALCHEMY_ENGINE_OPTIONS = {'pool_size': 10,'pool_recycle': 300,'pool_pre_ping': True}
3.3 应用初始化
app/init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from config import Config
import pymysqldb = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'login'def create_app(config_class=Config):app = Flask(__name__)app.config.from_object(config_class)# 确保数据库存在ensure_database_exists(app)db.init_app(app)login_manager.init_app(app)from app import routes, models# 创建数据库表with app.app_context():db.create_all()return appdef ensure_database_exists(app):"""确保 MySQL 数据库存在,如果不存在则创建"""# 提取数据库名称db_uri = app.config['SQLALCHEMY_DATABASE_URI']db_name = db_uri.split('/')[-1].split('?')[0]# 创建不指定数据库的连接temp_uri = '/'.join(db_uri.split('/')[:-1])temp_uri = temp_uri.replace('mysql+pymysql://', '')user_pass, host_port = temp_uri.split('@')user, password = user_pass.split(':')host, port = host_port.split(':') if ':' in host_port else (host_port, '3306')try:# 连接到 MySQL 服务器connection = pymysql.connect(host=host,user=user,password=password,port=int(port),charset='utf8mb4')with connection.cursor() as cursor:# 检查数据库是否存在cursor.execute(f"SHOW DATABASES LIKE '{db_name}'")result = cursor.fetchone()if not result:# 创建数据库cursor.execute(f"CREATE DATABASE {db_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")print(f"Database '{db_name}' created successfully.")connection.close()except Exception as e:print(f"Error ensuring database exists: {e}")# 如果无法连接到 MySQL,可以选择退出或使用回退方案raise
3.4 数据模型
app/models.py
from app import db, login_manager
from flask_login import UserMixin
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hashclass User(UserMixin, db.Model):__tablename__ = 'users' # 明确指定表名,避免使用保留字id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(64), unique=True, nullable=False, index=True)email = db.Column(db.String(120), unique=True, nullable=False, index=True)password_hash = db.Column(db.String(128))created_at = db.Column(db.DateTime, default=datetime.utcnow) # 添加创建时间字段tasks = db.relationship('Task', backref='author', lazy='dynamic', cascade='all, delete-orphan')def set_password(self, password):self.password_hash = generate_password_hash(password)def check_password(self, password):return check_password_hash(self.password_hash, password)def __repr__(self):return f'<User {self.username}>'class Task(db.Model):__tablename__ = 'tasks' # 明确指定表名id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(100), nullable=False)description = db.Column(db.Text)status = db.Column(db.String(20), default='pending') # pending, in_progress, completedcreated_at = db.Column(db.DateTime, default=datetime.utcnow)due_date = db.Column(db.DateTime)user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)def __repr__(self):return f'<Task {self.title}>'@login_manager.user_loader
def load_user(id):return User.query.get(int(id))
3.5 路由和视图
app/routes.py
from flask import render_template, redirect, url_for, flash, request
from flask_login import login_user, logout_user, current_user, login_required
from app import db
from app.models import User, Task
from app import create_app
from datetime import datetimeapp = create_app()@app.route('/')
@app.route('/index')
def index():return render_template('index.html')@app.route('/register', methods=['GET', 'POST'])
def register():if current_user.is_authenticated:return redirect(url_for('tasks'))if request.method == 'POST':username = request.form.get('username')email = request.form.get('email')password = request.form.get('password')if User.query.filter_by(username=username).first():flash('Username already exists')return redirect(url_for('register'))if User.query.filter_by(email=email).first():flash('Email already registered')return redirect(url_for('register'))user = User(username=username, email=email)user.set_password(password)db.session.add(user)db.session.commit()flash('Registration successful! Please log in.')return redirect(url_for('login'))return render_template('register.html')@app.route('/login', methods=['GET', 'POST'])
def login():if current_user.is_authenticated:return redirect(url_for('tasks'))if request.method == 'POST':username = request.form.get('username')password = request.form.get('password')remember_me = bool(request.form.get('remember_me'))user = User.query.filter_by(username=username).first()if user and user.check_password(password):login_user(user, remember=remember_me)next_page = request.args.get('next')return redirect(next_page) if next_page else redirect(url_for('tasks'))else:flash('Invalid username or password')return render_template('login.html')@app.route('/logout')
def logout():logout_user()return redirect(url_for('index'))@app.route('/tasks')
@login_required
def tasks():task_list = Task.query.filter_by(user_id=current_user.id).all()return render_template('tasks.html', tasks=task_list)@app.route('/add_task', methods=['POST'])
@login_required
def add_task():title = request.form.get('title')description = request.form.get('description')due_date_str = request.form.get('due_date')due_date = datetime.strptime(due_date_str, '%Y-%m-%d') if due_date_str else Nonetask = Task(title=title, description=description, due_date=due_date,user_id=current_user.id)db.session.add(task)db.session.commit()flash('Task added successfully!')return redirect(url_for('tasks'))@app.route('/update_task/<int:task_id>', methods=['POST'])
@login_required
def update_task(task_id):task = Task.query.get_or_404(task_id)if task.author != current_user:flash('You can only update your own tasks!')return redirect(url_for('tasks'))task.status = request.form.get('status')db.session.commit()flash('Task updated successfully!')return redirect(url_for('tasks'))@app.route('/delete_task/<int:task_id>')
@login_required
def delete_task(task_id):task = Task.query.get_or_404(task_id)if task.author != current_user:flash('You can only delete your own tasks!')return redirect(url_for('tasks'))db.session.delete(task)db.session.commit()flash('Task deleted successfully!')return redirect(url_for('tasks'))
3.6 基础模板
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 %}Task Manager{% endblock %}</title><link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body><nav><div class="nav-container"><a href="{{ url_for('index') }}">Task Manager</a><div class="nav-links">{% if current_user.is_authenticated %}<a href="{{ url_for('tasks') }}">My Tasks</a><a href="{{ url_for('logout') }}">Logout</a>{% else %}<a href="{{ url_for('login') }}">Login</a><a href="{{ url_for('register') }}">Register</a>{% endif %}</div></div></nav><div class="container">{% with messages = get_flashed_messages() %}{% if messages %}<div class="flash-messages">{% for message in messages %}<div class="flash-message">{{ message }}</div>{% endfor %}</div>{% endif %}{% endwith %}{% block content %}{% endblock %}</div>
</body>
</html>
3.7 主页模板
app/templates/index.html
{% extends "base.html" %}{% block content %}
<div class="hero"><h1>Welcome to Task Manager</h1><p>Organize your tasks and boost your productivity</p>{% if not current_user.is_authenticated %}<div class="cta-buttons"><a href="{{ url_for('register') }}" class="btn btn-primary">Get Started</a><a href="{{ url_for('login') }}" class="btn btn-secondary">Login</a></div>{% else %}<div class="cta-buttons"><a href="{{ url_for('tasks') }}" class="btn btn-primary">View Tasks</a></div>{% endif %}
</div>
{% endblock %}
3.8 登录模板
app/templates/login.html
{% extends "base.html" %}{% block title %}Login - Task Manager{% endblock %}{% block content %}
<div class="auth-form"><h2>Login</h2><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><div class="form-group"><label><input type="checkbox" name="remember_me"> Remember me</label></div><button type="submit" class="btn btn-primary">Login</button></form><p>Don't have an account? <a href="{{ url_for('register') }}">Register here</a></p>
</div>
{% endblock %}
3.9 注册模板
app/templates/register.html
{% extends "base.html" %}{% block title %}Register - Task Manager{% endblock %}{% block content %}
<div class="auth-form"><h2>Register</h2><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="email">Email</label><input type="email" id="email" name="email" required></div><div class="form-group"><label for="password">Password</label><input type="password" id="password" name="password" required></div><button type="submit" class="btn btn-primary">Register</button></form><p>Already have an account? <a href="{{ url_for('login') }}">Login here</a></p>
</div>
{% endblock %}
3.10 任务管理模板
app/templates/tasks.html
{% extends "base.html" %}{% block title %}My Tasks - Task Manager{% endblock %}{% block content %}
<div class="tasks-header"><h2>My Tasks</h2><button id="show-form-btn" class="btn btn-primary">Add New Task</button>
</div><div id="task-form" class="task-form" style="display: none;"><h3>Add New Task</h3><form method="POST" action="{{ url_for('add_task') }}"><div class="form-group"><label for="title">Title</label><input type="text" id="title" name="title" required></div><div class="form-group"><label for="description">Description</label><textarea id="description" name="description" rows="3"></textarea></div><div class="form-group"><label for="due_date">Due Date</label><input type="date" id="due_date" name="due_date"></div><button type="submit" class="btn btn-primary">Add Task</button></form>
</div><div class="tasks-list">{% if tasks %}{% for task in tasks %}<div class="task-card {% if task.status == 'completed' %}completed{% endif %}"><h3>{{ task.title }}</h3>{% if task.description %}<p>{{ task.description }}</p>{% endif %}<div class="task-meta"><span>Created: {{ task.created_at.strftime('%Y-%m-%d') }}</span>{% if task.due_date %}<span>Due: {{ task.due_date.strftime('%Y-%m-%d') }}</span>{% endif %}<span class="status {{ task.status }}">{{ task.status }}</span></div><div class="task-actions"><form method="POST" action="{{ url_for('update_task', task_id=task.id) }}"><select name="status" onchange="this.form.submit()"><option value="pending" {% if task.status == 'pending' %}selected{% endif %}>Pending</option><option value="in_progress" {% if task.status == 'in_progress' %}selected{% endif %}>In Progress</option><option value="completed" {% if task.status == 'completed' %}selected{% endif %}>Completed</option></select></form><a href="{{ url_for('delete_task', task_id=task.id) }}" class="btn btn-danger" onclick="return confirm('Are you sure?')">Delete</a></div></div>{% endfor %}{% else %}<p>No tasks yet. Add your first task!</p>{% endif %}
</div><script>document.getElementById('show-form-btn').addEventListener('click', function() {const form = document.getElementById('task-form');form.style.display = form.style.display === 'none' ? 'block' : 'none';});
</script>
{% endblock %}
3.11 样式文件
app/static/style.css
* {margin: 0;padding: 0;box-sizing: border-box;
}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.6;color: #333;background-color: #f5f5f5;
}.container {max-width: 1200px;margin: 0 auto;padding: 0 20px;
}/* Navigation */
nav {background-color: #2c3e50;color: white;padding: 1rem 0;
}.nav-container {display: flex;justify-content: space-between;align-items: center;max-width: 1200px;margin: 0 auto;padding: 0 20px;
}nav a {color: white;text-decoration: none;margin-right: 20px;
}nav a:hover {text-decoration: underline;
}.nav-links {display: flex;
}/* Buttons */
.btn {display: inline-block;padding: 10px 20px;border: none;border-radius: 4px;cursor: pointer;text-decoration: none;font-size: 16px;transition: background-color 0.3s;
}.btn-primary {background-color: #3498db;color: white;
}.btn-primary:hover {background-color: #2980b9;
}.btn-secondary {background-color: #95a5a6;color: white;
}.btn-secondary:hover {background-color: #7f8c8d;
}.btn-danger {background-color: #e74c3c;color: white;padding: 5px 10px;font-size: 14px;
}.btn-danger:hover {background-color: #c0392b;
}/* Hero section */
.hero {text-align: center;padding: 4rem 0;
}.hero h1 {font-size: 2.5rem;margin-bottom: 1rem;
}.hero p {font-size: 1.2rem;margin-bottom: 2rem;color: #666;
}.cta-buttons {display: flex;justify-content: center;gap: 1rem;
}/* Forms */
.auth-form, .task-form {max-width: 500px;margin: 2rem auto;padding: 2rem;background: white;border-radius: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}.form-group {margin-bottom: 1.5rem;
}label {display: block;margin-bottom: 0.5rem;font-weight: bold;
}input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
textarea,
select {width: 100%;padding: 10px;border: 1px solid #ddd;border-radius: 4px;font-size: 16px;
}/* Tasks */
.tasks-header {display: flex;justify-content: space-between;align-items: center;margin: 2rem 0;
}.tasks-list {display: grid;gap: 1.5rem;margin-top: 2rem;
}.task-card {background: white;padding: 1.5rem;border-radius: 8px;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}.task-card.completed {opacity: 0.7;border-left: 4px solid #2ecc71;
}.task-card h3 {margin-bottom: 0.5rem;
}.task-meta {display: flex;gap: 1rem;margin: 1rem 0;font-size: 0.9rem;color: #666;
}.status {padding: 3px 8px;border-radius: 12px;font-size: 0.8rem;font-weight: bold;
}.status.pending {background-color: #f39c12;color: white;
}.status.in_progress {background-color: #3498db;color: white;
}.status.completed {background-color: #2ecc71;color: white;
}.task-actions {display: flex;gap: 1rem;align-items: center;
}/* Flash messages */
.flash-messages {margin: 1rem 0;
}.flash-message {padding: 10px 15px;margin-bottom: 1rem;border-radius: 4px;background-color: #f8d7da;color: #721c24;border: 1px solid #f5c6cb;
}/* Responsive */
@media (max-width: 768px) {.nav-container {flex-direction: column;gap: 1rem;}.tasks-header {flex-direction: column;gap: 1rem;align-items: flex-start;}.task-meta {flex-direction: column;gap: 0.5rem;}.task-actions {flex-direction: column;align-items: flex-start;}
}
3.12 运行文件
run.py
from app import create_appapp = create_app()if __name__ == '__main__':app.run(debug=True)
3.13 依赖文件
requirements.txt
Flask==2.3.3
Flask-SQLAlchemy==3.0.5
Flask-Login==0.6.2
Werkzeug==2.3.7
PyMySQL==1.1.0 # 添加 PyMySQL 驱动
cryptography==41.0.4 # 可能需要用于加密连接
4. 数据库创建
4.1 数据库登录
运行前先确保MySQL服务器正常运行
登录MySQL
mysql -u root -p 1234
4.2 创建数据库和用户
CREATE DATABASE IF NOT EXISTS flask_task_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;CREATE USER 'flask_user'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON flask_task_manager.* TO 'flask_user'@'localhost';
FLUSH PRIVILEGES;
4.3 连接数据库
除了之前代码中的连接数据库方式外,还可以通过环境变量来配置数据库连接
export MYSQL_HOST=localhost
export MYSQL_USER=flask_user
export MYSQL_PASSWORD=your_password
export MYSQL_DB=flask_task_manager
export MYSQL_PORT=3306
5. 安装依赖
cmd窗口进入项目目录
cd flask_task_manager
创建虚拟环境并激活
python -m venv venv
venv\Scripts\activate
安装依赖
pip install -r requirements.txt
6. 运行程序
运行程序
python run.py
7. 访问
打开浏览器
访问地址
http:127.0.0.1:5000
8. 注意事项
-
字符集和排序规则:确保使用 utf8mb4 字符集和 utf8mb4_unicode_ci 排序规则,以支持所有 Unicode 字符(包括表情符号)。
-
MySQL 版本:确保你的 MySQL 版本是 5.7 或更高版本,以获得更好的性能和功能支持。
-
连接池:在生产环境中,使用连接池可以提高性能并管理数据库连接。
-
备份策略:定期备份 MySQL 数据库,因为与 SQLite 不同,MySQL 数据不是存储在单个文件中。
-
性能优化:对于大型应用,考虑添加适当的索引、使用数据库迁移工具(如 Alembic)以及实施缓存策略。
-
安全性:
不要在代码中硬编码数据库密码使用环境变量或安全的配置管理工具限制数据库用户的权限(遵循最小权限原则)
完成这些修改后,你的 Flask 应用将使用 MySQL 作为数据库后端,而不是 SQLite。这为应用提供了更好的扩展性和性能,特别是在生产环境中。
📜文末寄语
- 🟠关注我,获取更多内容。
- 🟡技术动态、实战教程、问题解决方案等内容持续更新中。
- 🟢《全栈知识库》技术交流和分享社区,集结全栈各领域开发者,期待你的加入。
- 🔵加入开发者的《专属社群》,分享交流,技术之路不再孤独,一起变强。
- 🟣点击下方名片获取更多内容🍭🍭🍭👇