第19篇:python高级编程进阶:使用Flask进行Web开发
第19篇:python高级编程进阶:使用Flask进行Web开发
内容简介
在第18篇文章中,我们介绍了Web开发的基础知识,并使用Flask框架构建了一个简单的Web应用。本篇文章将深入探讨Flask的高级功能,涵盖模板引擎(Jinja2)、表单处理、数据库集成以及用户认证等主题。通过系统的讲解和实战案例,您将掌握构建功能更为丰富和复杂的Web应用所需的技能。
目录
- Flask的深入使用
- Flask扩展
- 蓝图(Blueprints)
- 应用工厂模式
- 模板引擎(Jinja2)
- Jinja2简介
- 模板继承
- 控制结构
- 宏与自定义过滤器
- 表单处理
- 使用Flask-WTF
- 表单验证
- 处理表单数据
- 数据库集成
- 使用Flask-SQLAlchemy
- 数据库迁移
- 关系数据库操作
- 用户认证
- 使用Flask-Login
- 用户注册与登录
- 权限管理
- 示例项目:博客系统
- 项目结构
- 实现用户认证
- 创建和管理博客文章
- 评论功能
- 常见问题及解决方法
- 问题1:如何处理表单的CSRF保护?
- 问题2:如何优化数据库查询性能?
- 问题3:如何实现密码的安全存储?
- 问题4:如何部署Flask应用到生产环境?
- 总结
Flask的深入使用
Flask扩展
Flask的强大之处在于其丰富的扩展生态系统,这些扩展能够为您的应用添加各种功能,如数据库集成、表单处理、用户认证等。常用的Flask扩展包括:
- Flask-WTF:集成了WTForms,用于表单处理和验证。
- Flask-Login:用于用户认证和会话管理。
- Flask-Migrate:基于Alembic的数据库迁移工具。
- Flask-Mail:用于发送电子邮件。
- Flask-Admin:提供管理后台界面。
- Flask-RESTful:用于构建RESTful API。
蓝图(Blueprints)
蓝图是Flask中组织大型应用的一种方式。它允许您将应用的不同部分拆分成独立的组件或模块,从而提高代码的可维护性和可扩展性。
创建蓝图的步骤:
-
定义蓝图:
# blog/routes.py from flask import Blueprint, render_templateblog_bp = Blueprint('blog', __name__, url_prefix='/blog')@blog_bp.route('/') def index():return render_template('blog/index.html')
-
注册蓝图:
# app.py from flask import Flask from blog.routes import blog_bpapp = Flask(__name__) app.register_blueprint(blog_bp)if __name__ == '__main__':app.run(debug=True)
应用工厂模式
应用工厂模式是一种创建Flask应用实例的设计模式,尤其适用于大型项目。它允许在创建应用实例时动态配置应用,提高了灵活性和可测试性。
实现应用工厂模式:
-
创建工厂函数:
# app/__init__.py from flask import Flask from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()def create_app(config_filename=None):app = Flask(__name__)if config_filename:app.config.from_pyfile(config_filename)else:app.config.from_object('config.default')db.init_app(app)from .blog.routes import blog_bpapp.register_blueprint(blog_bp)return app
-
运行应用:
# run.py from app import create_appapp = create_app('config/development.py')if __name__ == '__main__':app.run()
模板引擎(Jinja2)
Jinja2简介
Jinja2是Flask默认使用的模板引擎,它允许您在HTML中嵌入Python代码,从而实现动态内容渲染。Jinja2支持模板继承、控制结构、宏等高级功能,使模板编写更加简洁和高效。
模板继承
模板继承是Jinja2的一大特性,允许您定义一个基础模板,并在此基础上创建子模板,避免重复代码。
创建基础模板:
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head><title>{% block title %}我的网站{% endblock %}</title><link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body><header><h1>我的网站</h1><nav><a href="{{ url_for('home') }}">首页</a> |<a href="{{ url_for('about') }}">关于</a> |<a href="{{ url_for('blog.index') }}">博客</a> |<a href="{{ url_for('contact') }}">联系</a></nav></header><main>{% block content %}{% endblock %}</main><footer><p>© 2025 我的公司</p></footer>
</body>
</html>
创建子模板:
<!-- templates/blog/index.html -->
{% extends 'base.html' %}{% block title %}博客 - 我的网站{% endblock %}{% block content %}<h2>博客文章</h2><ul>{% for post in posts %}<li><a href="{{ url_for('blog.view_post', post_id=post.id) }}">{{ post.title }}</a></li>{% else %}<li>暂无文章。</li>{% endfor %}</ul>
{% endblock %}
控制结构
Jinja2支持多种控制结构,如条件语句和循环,帮助您根据数据动态生成内容。
条件语句示例:
<!-- templates/user_profile.html -->
{% extends 'base.html' %}{% block title %}用户: {{ user.username }}{% endblock %}{% block content %}<h2>用户: {{ user.username }}</h2><p>邮箱: {{ user.email }}</p>{% if user.is_admin %}<p>角色: 管理员</p>{% else %}<p>角色: 普通用户</p>{% endif %}
{% endblock %}
循环示例:
<!-- templates/blog/post_list.html -->
{% extends 'base.html' %}{% block title %}博客文章列表{% endblock %}{% block content %}<h2>博客文章</h2><ul>{% for post in posts %}<li><a href="{{ url_for('blog.view_post', post_id=post.id) }}">{{ post.title }}</a><span> - {{ post.date_posted.strftime('%Y-%m-%d') }}</span></li>{% else %}<li>暂无文章发布。</li>{% endfor %}</ul>
{% endblock %}
宏与自定义过滤器
宏是Jinja2中的一种可重用模板片段,类似于函数。自定义过滤器允许您扩展Jinja2的功能,自定义数据的展示方式。
定义和使用宏:
-
定义宏:
<!-- templates/macros.html --> {% macro render_post(post) %}<div class="post"><h3><a href="{{ url_for('blog.view_post', post_id=post.id) }}">{{ post.title }}</a></h3><p>{{ post.content[:100] }}...</p><p><small>发布于 {{ post.date_posted.strftime('%Y-%m-%d') }}</small></p></div> {% endmacro %}
-
使用宏:
<!-- templates/blog/index.html --> {% extends 'base.html' %} {% import 'macros.html' as macros %}{% block title %}博客 - 我的网站{% endblock %}{% block content %}<h2>博客文章</h2>{% for post in posts %}{{ macros.render_post(post) }}{% else %}<p>暂无文章发布。</p>{% endfor %} {% endblock %}
定义自定义过滤器:
-
创建过滤器:
# app/filters.py from flask import Markupdef nl2br(value):return Markup(value.replace('\n', '<br>'))
-
注册过滤器:
# app/__init__.py from flask import Flask from .filters import nl2brdef create_app(config_filename=None):app = Flask(__name__)# 配置和初始化扩展app.jinja_env.filters['nl2br'] = nl2brreturn app
-
使用过滤器:
<!-- templates/blog/view_post.html --> {% extends 'base.html' %}{% block title %}{{ post.title }}{% endblock %}{% block content %}<h2>{{ post.title }}</h2><p><small>发布于 {{ post.date_posted.strftime('%Y-%m-%d') }}</small></p><div>{{ post.content | nl2br }}</div> {% endblock %}
表单处理
使用Flask-WTF
Flask-WTF是Flask的一个扩展,集成了WTForms,用于简化表单的创建、渲染和验证过程。
安装Flask-WTF:
pip install Flask-WTF
表单验证
Flask-WTF提供了丰富的表单验证功能,确保用户输入的数据符合预期。
创建表单类:
# app/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Email, Length, EqualToclass RegistrationForm(FlaskForm):username = StringField('用户名', validators=[DataRequired(), Length(min=4, max=25)])email = StringField('邮箱', validators=[DataRequired(), Email()])password = PasswordField('密码', validators=[DataRequired(), Length(min=6)])confirm_password = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password')])submit = SubmitField('注册')class LoginForm(FlaskForm):email = StringField('邮箱', validators=[DataRequired(), Email()])password = PasswordField('密码', validators=[DataRequired()])submit = SubmitField('登录')
处理表单数据
在视图函数中处理表单的提交和验证结果。
注册视图函数:
# app/auth/routes.py
from flask import Blueprint, render_template, redirect, url_for, flash
from .forms import RegistrationForm
from app import db
from app.models import Userauth_bp = Blueprint('auth', __name__, url_prefix='/auth')@auth_bp.route('/register', methods=['GET', 'POST'])
def register():form = RegistrationForm()if form.validate_on_submit():user = User(username=form.username.data, email=form.email.data)user.set_password(form.password.data)db.session.add(user)db.session.commit()flash('注册成功!请登录。', 'success')return redirect(url_for('auth.login'))return render_template('auth/register.html', form=form)
模板文件:
<!-- templates/auth/register.html -->
{% extends 'base.html' %}{% block title %}注册{% endblock %}{% block content %}<h2>注册</h2><form method="POST" action="{{ url_for('auth.register') }}">{{ form.hidden_tag() }}<p>{{ form.username.label }}<br>{{ form.username(size=32) }}<br>{% for error in form.username.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.email.label }}<br>{{ form.email(size=32) }}<br>{% for error in form.email.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.password.label }}<br>{{ form.password(size=32) }}<br>{% for error in form.password.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.confirm_password.label }}<br>{{ form.confirm_password(size=32) }}<br>{% for error in form.confirm_password.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.submit() }}</p></form>
{% endblock %}
数据库集成
使用Flask-SQLAlchemy
Flask-SQLAlchemy是Flask的一个扩展,简化了与数据库的交互。它基于SQLAlchemy ORM,提供了强大的数据库操作能力。
安装Flask-SQLAlchemy:
pip install Flask-SQLAlchemy
配置数据库
在应用配置中设置数据库URI。
# config/development.py
SQLALCHEMY_DATABASE_URI = 'sqlite:///site.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = 'your_secret_key'
定义模型
使用Flask-SQLAlchemy定义数据库模型。
# app/models.py
from app import db
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixinclass User(db.Model, UserMixin):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(25), unique=True, nullable=False)email = db.Column(db.String(120), unique=True, nullable=False)password_hash = db.Column(db.String(128), nullable=False)posts = db.relationship('Post', backref='author', lazy=True)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)class Post(db.Model):id = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(100), nullable=False)date_posted = db.Column(db.DateTime, nullable=False, default=db.func.now())content = db.Column(db.Text, nullable=False)user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
数据库迁移
Flask-Migrate基于Alembic,提供数据库迁移的能力,帮助您管理数据库模式的变化。
安装Flask-Migrate:
pip install Flask-Migrate
配置迁移:
# app/__init__.py
from flask_migrate import Migrate
from . import dbdef create_app(config_filename=None):app = Flask(__name__)app.config.from_pyfile(config_filename)db.init_app(app)migrate = Migrate(app, db)# 注册蓝图等return app
初始化迁移环境:
flask db init
创建迁移脚本:
flask db migrate -m "创建用户和博客模型"
应用迁移:
flask db upgrade
关系数据库操作
利用SQLAlchemy ORM进行数据库操作,实现对象与数据库表的映射。
创建新用户和文章:
# 创建新用户
new_user = User(username='张三', email='zhangsan@example.com')
new_user.set_password('securepassword')
db.session.add(new_user)
db.session.commit()# 创建新文章
post = Post(title='第一篇博客', content='这是我的第一篇博客文章。', author=new_user)
db.session.add(post)
db.session.commit()
查询数据:
# 查询所有用户
users = User.query.all()# 查询特定用户
user = User.query.filter_by(username='张三').first()# 查询用户的所有文章
user_posts = user.posts
更新数据:
user.email = 'newemail@example.com'
db.session.commit()
删除数据:
db.session.delete(user)
db.session.commit()
用户认证
使用Flask-Login
Flask-Login是Flask的一个扩展,简化了用户认证和会话管理的过程。
安装Flask-Login:
pip install Flask-Login
配置Flask-Login
初始化Flask-Login:
# app/__init__.py
from flask_login import LoginManagerdef create_app(config_filename=None):app = Flask(__name__)app.config.from_pyfile(config_filename)db.init_app(app)migrate = Migrate(app, db)login_manager = LoginManager()login_manager.login_view = 'auth.login'login_manager.init_app(app)from .models import User@login_manager.user_loaderdef load_user(user_id):return User.query.get(int(user_id))# 注册蓝图等return app
用户注册与登录
注册视图:
已在表单处理部分展示。
登录视图:
# app/auth/routes.py
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_user, logout_user, login_required
from .forms import LoginForm
from app.models import Userauth_bp = Blueprint('auth', __name__, url_prefix='/auth')@auth_bp.route('/login', methods=['GET', 'POST'])
def login():form = LoginForm()if form.validate_on_submit():user = User.query.filter_by(email=form.email.data).first()if user and user.check_password(form.password.data):login_user(user)flash('登录成功!', 'success')next_page = request.args.get('next')return redirect(next_page) if next_page else redirect(url_for('home'))else:flash('登录失败,请检查邮箱和密码。', 'danger')return render_template('auth/login.html', form=form)@auth_bp.route('/logout')
@login_required
def logout():logout_user()flash('已注销登录。', 'info')return redirect(url_for('home'))
登录模板:
<!-- templates/auth/login.html -->
{% extends 'base.html' %}{% block title %}登录{% endblock %}{% block content %}<h2>登录</h2><form method="POST" action="{{ url_for('auth.login') }}">{{ form.hidden_tag() }}<p>{{ form.email.label }}<br>{{ form.email(size=32) }}<br>{% for error in form.email.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.password.label }}<br>{{ form.password(size=32) }}<br>{% for error in form.password.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.submit() }}</p></form>
{% endblock %}
权限管理
根据用户的角色或权限控制对特定资源的访问。
定义用户角色:
在用户模型中添加角色字段。
# app/models.py
class User(db.Model, UserMixin):# 其他字段role = db.Column(db.String(20), nullable=False, default='user')def is_admin(self):return self.role == 'admin'
装饰器实现权限控制:
# app/decorators.py
from functools import wraps
from flask import abort
from flask_login import current_userdef admin_required(f):@wraps(f)def decorated_function(*args, **kwargs):if not current_user.is_admin():abort(403)return f(*args, **kwargs)return decorated_function
应用装饰器:
# app/admin/routes.py
from flask import Blueprint, render_template
from flask_login import login_required
from app.decorators import admin_requiredadmin_bp = Blueprint('admin', __name__, url_prefix='/admin')@admin_bp.route('/')
@login_required
@admin_required
def dashboard():return render_template('admin/dashboard.html')
示例项目:博客系统
为了综合应用上述知识,本节将带您构建一个功能完善的博客系统,包含用户注册与登录、博客文章管理及评论功能。
项目结构
flask_blog/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── forms.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ ├── blog/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── auth/
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ ├── blog/
│ │ │ ├── index.html
│ │ │ ├── create_post.html
│ │ │ └── view_post.html
│ │ └── admin/
│ │ └── dashboard.html
│ └── static/
│ └── css/
│ └── styles.css
├── migrations/
├── config/
│ ├── __init__.py
│ ├── default.py
│ └── development.py
├── run.py
└── requirements.txt
实现用户认证
用户注册与登录:
已在用户认证部分展示。
创建和管理博客文章
创建博客文章表单:
# app/blog/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Lengthclass PostForm(FlaskForm):title = StringField('标题', validators=[DataRequired(), Length(min=1, max=100)])content = TextAreaField('内容', validators=[DataRequired()])submit = SubmitField('发布')
博客视图函数:
# app/blog/routes.py
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_required, current_user
from app import db
from app.models import Post
from .forms import PostFormblog_bp = Blueprint('blog', __name__, url_prefix='/blog')@blog_bp.route('/')
def index():posts = Post.query.order_by(Post.date_posted.desc()).all()return render_template('blog/index.html', posts=posts)@blog_bp.route('/create', methods=['GET', 'POST'])
@login_required
def create_post():form = PostForm()if form.validate_on_submit():post = Post(title=form.title.data, content=form.content.data, author=current_user)db.session.add(post)db.session.commit()flash('博客文章发布成功!', 'success')return redirect(url_for('blog.index'))return render_template('blog/create_post.html', form=form)@blog_bp.route('/post/<int:post_id>')
def view_post(post_id):post = Post.query.get_or_404(post_id)return render_template('blog/view_post.html', post=post)
创建博客文章模板:
<!-- templates/blog/create_post.html -->
{% extends 'base.html' %}{% block title %}创建博客文章{% endblock %}{% block content %}<h2>创建博客文章</h2><form method="POST" action="{{ url_for('blog.create_post') }}">{{ form.hidden_tag() }}<p>{{ form.title.label }}<br>{{ form.title(size=64) }}<br>{% for error in form.title.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.content.label }}<br>{{ form.content(rows=10, cols=70) }}<br>{% for error in form.content.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.submit() }}</p></form>
{% endblock %}
评论功能
定义评论模型:
# app/models.py
class Comment(db.Model):id = db.Column(db.Integer, primary_key=True)content = db.Column(db.Text, nullable=False)date_posted = db.Column(db.DateTime, nullable=False, default=db.func.now())user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
创建评论表单:
# app/blog/forms.py
class CommentForm(FlaskForm):content = TextAreaField('评论', validators=[DataRequired(), Length(min=1, max=500)])submit = SubmitField('提交评论')
更新视图函数以处理评论:
# app/blog/routes.py
from .forms import PostForm, CommentForm
from app.models import Comment@blog_bp.route('/post/<int:post_id>', methods=['GET', 'POST'])
def view_post(post_id):post = Post.query.get_or_404(post_id)form = CommentForm()if form.validate_on_submit():comment = Comment(content=form.content.data, author=current_user, post=post)db.session.add(comment)db.session.commit()flash('评论提交成功!', 'success')return redirect(url_for('blog.view_post', post_id=post.id))comments = Comment.query.filter_by(post_id=post.id).order_by(Comment.date_posted.asc()).all()return render_template('blog/view_post.html', post=post, form=form, comments=comments)
更新评论模板:
<!-- templates/blog/view_post.html -->
{% extends 'base.html' %}{% block title %}{{ post.title }}{% endblock %}{% block content %}<h2>{{ post.title }}</h2><p><small>发布于 {{ post.date_posted.strftime('%Y-%m-%d') }}</small></p><div>{{ post.content | nl2br }}</div><hr><h3>评论</h3>{% for comment in comments %}<div class="comment"><p>{{ comment.content | nl2br }}</p><p><small>由 {{ comment.author.username }} 于 {{ comment.date_posted.strftime('%Y-%m-%d %H:%M') }}</small></p></div>{% else %}<p>暂无评论。</p>{% endfor %}<hr>{% if current_user.is_authenticated %}<h4>添加评论</h4><form method="POST" action="{{ url_for('blog.view_post', post_id=post.id) }}">{{ form.hidden_tag() }}<p>{{ form.content.label }}<br>{{ form.content(rows=4, cols=70) }}<br>{% for error in form.content.errors %}<span class="error">{{ error }}</span>{% endfor %}</p><p>{{ form.submit() }}</p></form>{% else %}<p><a href="{{ url_for('auth.login') }}">登录</a>后可添加评论。</p>{% endif %}
{% endblock %}
常见问题及解决方法
问题1:如何处理表单的CSRF保护?
原因:跨站请求伪造(CSRF)是一种常见的Web攻击,Flask-WTF通过生成和验证CSRF令牌来防止此类攻击。
解决方法:
-
启用CSRF保护:
在应用配置中设置
SECRET_KEY
,Flask-WTF将自动启用CSRF保护。# config/development.py SECRET_KEY = 'your_secret_key'
-
在表单中包含隐藏的CSRF令牌:
使用
{{ form.hidden_tag() }}
在表单中插入CSRF令牌。<!-- 示例表单 --> <form method="POST" action="{{ url_for('auth.login') }}">{{ form.hidden_tag() }}<!-- 其他表单字段 --> </form>
-
验证CSRF令牌:
Flask-WTF会自动在表单提交时验证CSRF令牌,无需手动处理。
问题2:如何优化数据库查询性能?
原因:在处理大量数据时,未优化的查询可能导致性能瓶颈,影响应用响应速度。
解决方法:
-
使用懒加载和即时加载:
根据需求选择适当的加载策略,避免不必要的数据库查询。
# 使用lazy='joined'进行即时加载 posts = Post.query.options(db.joinedload(Post.author)).all()
-
添加索引:
为频繁查询的字段添加数据库索引,提高查询速度。
# app/models.py class User(db.Model, UserMixin):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(25), unique=True, nullable=False, index=True)email = db.Column(db.String(120), unique=True, nullable=False, index=True)# 其他字段
-
分页查询:
对大量数据进行分页展示,减少单次查询的数据量。
# app/blog/routes.py @blog_bp.route('/') def index():page = request.args.get('page', 1, type=int)posts = Post.query.order_by(Post.date_posted.desc()).paginate(page=page, per_page=5)return render_template('blog/index.html', posts=posts)
-
使用原生SQL查询:
在复杂查询场景下,使用原生SQL语句可能比ORM查询更高效。
# 使用db.engine执行原生SQL result = db.engine.execute('SELECT * FROM post WHERE user_id = :user_id', user_id=1) for row in result:print(row)
问题3:如何实现密码的安全存储?
原因:用户密码的安全存储对于保护用户隐私和防止数据泄露至关重要。
解决方法:
-
使用哈希算法:
不要以明文形式存储密码,而应使用强哈希算法进行加密。
from werkzeug.security import generate_password_hash, check_password_hashclass User(db.Model, UserMixin):# 其他字段password_hash = db.Column(db.String(128), nullable=False)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)
-
使用盐(Salt):
哈希算法会自动为密码添加盐,提高安全性,防止彩虹表攻击。
-
定期更新哈希算法:
随着技术的发展,定期评估和更新哈希算法,以应对新的安全威胁。
问题4:如何部署Flask应用到生产环境?
原因:开发环境与生产环境存在差异,直接在生产环境中运行Flask内置服务器不安全且不高效。
解决方法:
-
使用WSGI服务器:
部署Flask应用时,应使用专业的WSGI服务器,如Gunicorn或uWSGI。
# 使用Gunicorn pip install gunicorn gunicorn run:app
-
配置反向代理:
使用Nginx或Apache作为反向代理服务器,处理客户端请求并转发给WSGI服务器。
Nginx示例配置:
server {listen 80;server_name your_domain.com;location / {proxy_pass http://127.0.0.1:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}location /static/ {alias /path/to/your/flask_app/app/static/;} }
-
启用HTTPS:
使用SSL证书为您的网站启用HTTPS,提高数据传输的安全性。可以使用Let’s Encrypt免费获取SSL证书。
-
配置环境变量:
不要将敏感信息(如
SECRET_KEY
、数据库URI)硬编码在代码中,而应通过环境变量配置。export FLASK_ENV=production export SECRET_KEY='your_production_secret_key' export SQLALCHEMY_DATABASE_URI='your_production_db_uri'
-
日志管理:
配置日志记录,监控应用的运行状态和错误信息。
-
使用容器化:
使用Docker等容器技术,简化部署过程,提高环境一致性。
Dockerfile示例:
FROM python:3.9-slimWORKDIR /appCOPY requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txtCOPY . .CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "run:app"]
示例项目:博客系统
项目结构
flask_blog/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── forms.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ ├── blog/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── auth/
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ ├── blog/
│ │ │ ├── index.html
│ │ │ ├── create_post.html
│ │ │ └── view_post.html
│ │ └── admin/
│ │ └── dashboard.html
│ └── static/
│ └── css/
│ └── styles.css
├── migrations/
├── config/
│ ├── __init__.py
│ ├── default.py
│ └── development.py
├── run.py
└── requirements.txt
实现用户认证
用户注册与登录:
见前述用户认证部分,确保用户能够注册新账号并登录。
创建和管理博客文章
创建文章视图:
见前述创建博客文章表单和博客视图函数部分。
评论功能
定义评论模型:
见前述评论功能部分,确保用户能够对文章进行评论。
总结
在本篇文章中,我们深入探讨了Flask框架的高级功能,包括扩展的使用、蓝图的组织方式、应用工厂模式的实现、模板引擎Jinja2的高级特性、表单处理、数据库集成以及用户认证。通过详细的代码示例和实战项目——博客系统,您已经掌握了构建功能丰富且结构清晰的Web应用所需的核心技能。
学习建议:
- 构建自己的项目:尝试扩展博客系统,添加更多功能,如标签管理、文章分类、搜索功能等,巩固所学知识。
- 学习更多Flask扩展:探索如Flask-Admin、Flask-Mail、Flask-RESTful等扩展,提升应用的功能和用户体验。
- 优化应用性能:研究Flask应用的性能优化技巧,如缓存策略、数据库优化、异步任务处理等。
- 安全性提升:深入了解Web应用的安全性,学习防范常见的安全漏洞,如SQL注入、XSS攻击等。
- 部署与运维:学习如何将Flask应用部署到不同的平台,并掌握基本的运维技能,确保应用的稳定运行。
- 参与开源社区:通过参与Flask相关的开源项目,学习业界最佳实践,提升编程和协作能力。
- 持续学习:关注Flask和Web开发的最新动态,阅读官方文档和相关书籍,如《Flask Web Development》以保持知识的更新。
如果您有任何问题或需要进一步的帮助,请随时在评论区留言或联系相关技术社区。
相关文章:
第19篇:python高级编程进阶:使用Flask进行Web开发
第19篇:python高级编程进阶:使用Flask进行Web开发 内容简介 在第18篇文章中,我们介绍了Web开发的基础知识,并使用Flask框架构建了一个简单的Web应用。本篇文章将深入探讨Flask的高级功能,涵盖模板引擎(Ji…...
jEasyUI 创建复杂布局
jEasyUI 创建复杂布局 引言 jEasyUI 是一款基于 jQuery 的开源 UI 框架,它提供了一套丰富的 UI 组件,帮助开发者快速构建美观、易用的 Web 应用。在开发过程中,复杂布局的创建往往是一个挑战。本文将详细介绍如何使用 jEasyUI 创建复杂布局,帮助开发者提升工作效率。 前…...
前端【8】HTML+CSS+javascript实战项目----实现一个简单的待办事项列表 (To-Do List)
目录 一、功能需求 二、 HTML 三、CSS 四、js 1、绑定事件与初始设置 2.、绑定事项 (1)添加操作: (2)完成操作 (3)删除操作 (4)修改操作 3、完整js代码 总结…...
java爬虫工具Jsoup学习
目录 前言 一、基本使用 二、爬取豆瓣电影的案例 三、Jsoup能做什么? 四、Jsoup相关概念 五、Jsoup获取文档 六、定位选择元素 七、获取数据 八、具体案例 前言 JSoup是一个用于处理HTML的Java库,它提供了一个非常方便类似于使用DOM࿰…...
RabbitMQ模块新增消息转换器
文章目录 1.目录结构2.代码1.pom.xml 排除logging2.RabbitMQConfig.java3.RabbitMQAutoConfiguration.java 1.目录结构 2.代码 1.pom.xml 排除logging <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/PO…...
大话特征工程:1.维数灾难与特征轮回
一、维度深渊 公元 2147 年,人类文明进入了数据驱动的超级智能时代。从金融到医疗,从教育到娱乐,所有决策都仰赖“全维计算网络”(高维特征空间)。这套系统将全球所有信息抽象成数以亿计的多维特征(…...
学院失物招领 app 的设计与实现
标题:学院失物招领 app 的设计与实现 内容:1.摘要 随着移动互联网的普及和智能手机的广泛应用,越来越多的人开始使用手机应用程序来解决生活中的各种问题。在大学校园中,失物招领是一个常见的问题,每年都有大量的学生丢失或捡到物品。为了解…...
std::function的简易实现
本节我们来实现一个简易的std::function 我们知道std::function是用来包装可调用对象的,在C中,可调用对象包括 普通函数、lambda表达式、重载了()操作符的类对象、类静态函数、类成员函数这几类。 C程序的编译顺序:预处理(xxx.i) 编译(xxx.…...
笔试-二维数组1
应用 快递业务有N个站点,1<N<10000;站点0、站点1可达,记作0-1;如果0-1、1-2,则站点0、站点2可达,记作0-2;s[i][j]1表示i-j可达,反之s[i][j]0表示i-j不可达;s[i][j…...
【Pytest】生成html报告中,中文乱码问题解决方案
import pytestif __name__ "__main__":# 只运行 tests 目录下的测试用例,并生成 HTML 报告pytest.main([-v, -s, --htmlreport.html, tests])可以以上方式生成,也可以在pytest.ini中设置 [pytest] addopts --htmlreport.html --self-contai…...
汽车网络信息安全-ISO/SAE 21434解析(下)
目录 第十二~十四章 - 后开发阶段 1. 十二章节 - 生产 2. 十三章节 - 运营与维护 网络安全事件响应 更新 3. 十四章节 - 结束网络安全支持和停用 结束网络安全支持 报废 第十五章 - TARA分析方法 1. 概述 2. 资产识别 3. 威胁场景识别 4. 影响评级 5. 攻击路径分…...
局域网中 Windows 与 Mac 互相远程连接的最佳方案
由于工作需要,经常需要远程连接或登录到几台不同的工作用机上进行操作。 下面基于免费、高体验等基本诉求,简要记录几种不同场景下的实践方案选择,仅供参考。如您有更简单且更优的方案,欢迎一起探讨。 1 远程桌面连接的几种不同…...
Qt调用ffmpeg库录屏并进行UDP组播推流
基于以下参考链接,采用其界面和程序框架,实现实时推送UDP组播视频流,替换原拉流功能 https://blog.csdn.net/u012532263/article/details/102736700 源码在windows(qt-opensource-windows-x86-5.12.9.exe)、ubuntu20.…...
机器学习 - 初学者需要弄懂的一些线性代数的概念
一、单位矩阵 在数学中,单位矩阵是一个方阵,其主对角线上的元素全为1,其余元素全为0。单位矩阵在矩阵乘法中起到类似于数字1在数值乘法中的作用,即任何矩阵与单位矩阵相乘,结果仍为原矩阵本身。 单位矩阵的定义&…...
vscode无法格式化go代码的问题
CTRLshiftp 点击Go:Install/Update Tools 点击全选,OK!...
实验二 数据库的附加/分离、导入/导出与备份/还原
实验二 数据库的附加/分离、导入/导出与备份/还原 一、实验目的 1、理解备份的基本概念,掌握各种备份数据库的方法。 2、掌握如何从备份中还原数据库。 3、掌握数据库中各种数据的导入/导出。 4、掌握数据库的附加与分离,理解数据库的附加与分离的作用。…...
基于Django的个人博客系统的设计与实现
【Django】基于Django的个人博客系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 系统采用Python作为主要开发语言,结合Django框架构建后端逻辑,并运用J…...
PostgreSQL TRUNCATE TABLE 操作详解
PostgreSQL TRUNCATE TABLE 操作详解 引言 在数据库管理中,经常需要对表进行操作以保持数据的有效性和一致性。TRUNCATE TABLE 是 PostgreSQL 中一种高效删除表内所有记录的方法。本文将详细探讨 PostgreSQL 中 TRUNCATE TABLE 的使用方法、性能优势以及注意事项。 什么是 …...
黑盒/白盒运维监控
运维监控分为黑盒和白盒 黑盒:不深入代码,在系统角度看TPS,延迟等指标 白盒:深入代码分析,通过日志捕捉,以及主动上报告警等来进行监控 黑盒监控: 1. 页面功能:域名是否可访问&…...
日志收集Day007
1.配置ES集群TLS认证: (1)elk101节点生成证书文件 cd /usr/share/elasticsearch ./bin/elasticsearch-certutil cert -out config/elastic-certificates.p12 -pass "" --days 3650 (2)elk101节点为证书文件修改属主和属组 chown elasticsearch:elasticsearch con…...
微信小程序1.1 微信小程序介绍
1.1 微信小程序介绍 内容提要 1.1 什么是微信小程序 1.2 微信小程序的功能 1.3 微信小程序使用场景 1.4 微信小程序能取代App吗 1.5 微信小程序的发展历程 1.6微信小程序带来的机会...
Leetcode 3434. Maximum Frequency After Subarray Operation
Leetcode 3434. Maximum Frequency After Subarray Operation 1. 解题思路2. 代码实现 题目链接:3434. Maximum Frequency After Subarray Operation 1. 解题思路 这一题的话我们只需要考察所有的数 i i i转换为 k k k时所能够形成的最大的值。 而对于这个问题&…...
6. 使用springboot做一个音乐播放器软件项目【1.0版项目完结】附带源码~
#万物OOP 注意: 本项目只实现播放音乐和后台管理系统。 不分享任何音乐歌曲资源。 上一篇文章我们 做了音乐播放器后台的功能。参考地址: https://jsonll.blog.csdn.net/article/details/145214363 这个项目已经好几天也没更新了,因为临近放…...
php twig模板引擎详细使用教程
php twig模板引擎 1. 什么是Twig模板引擎 Twig是一个强大且灵活的PHP模板引擎,它提供了一种更简洁和可扩展的方法来创建PHP应用程序的视图层。Twig模板引擎旨在将设计与业务逻辑分离,并为开发人员提供一种更加清晰和易于维护的方式来构建网页。Twig由S…...
【Java设计模式-7】责任链模式:我是流水线的一员
一、责任链(Chain of Responsibility Patten)模式是个啥? 想象一下,你要请假。你先把请假申请交给了小组长,小组长一看,这事儿他能决定,就直接批了。要是小组长觉得这事儿得往上汇报࿰…...
Spring Boot应用中实现基于JWT的登录拦截器,以保证未登录用户无法访问指定的页面
目录 一、配置拦截器进行登录校验 1. 在config层设置拦截器 2. 实现LoginInterceptor拦截器 3. 创建JWT工具类 4. 在登录时创建JWT并存入Cookie 二、配置JWT依赖和环境 1. 添加JWT依赖 2. 配置JWT环境 本篇博客将为大家介绍了如何在Spring Boot应用中实现基于JWT的登录…...
【2025年数学建模美赛F题】(顶刊论文绘图)模型代码+论文
全球网络犯罪与网络安全政策的多维度分析及效能评估 摘要1 Introduction1.1 Problem Background1.2Restatement of the Problem1.3 Literature Review1.4 Our Work 2 Assumptions and Justifications数据完整性与可靠性假设:法律政策独立性假设:人口统计…...
计算机网络之链路层
本文章目录结构出自于《王道计算机考研 计算机网络_哔哩哔哩_bilibili》 02 数据链路层 在网上看到其他人做了详细的笔记,就不再多余写了,直接参考着学习吧。 1 详解数据链路层-数据链路层的功能【王道计算机网络笔记】_wx63088f6683f8f的技术博客_51C…...
随笔十七、eth0单网卡绑定双ip的问题
在调试语音对讲过程中遇到过一个“奇怪”问题:泰山派作为一端,可以收到对方发来的语音,而对方不能收到泰山派发出的语音。 用wireshark抓包UDP发现,泰山派发送的地址是192.168.1.30,而给泰山派实际设置的静态地址是19…...
coffee销售数据集分析:基于时间趋势分析的实操练习
**文章说明:**对coffee销售数据集的简单分析练习(时间趋势分析练习),主要是为了强化利用python进行数据分析的实操能力。属于个人的练习文章。 **注:**这是我第一次使用md格式编辑博客文章,排版上还是不是很…...
在 Vue 3 中,怎么管理环境变量
在 Vue 3 中,环境变量管理是通过 .env 文件来进行的,利用这些文件可以让开发者根据不同的环境(开发、生产、测试等)配置不同的变量。这一机制由 Vite 构建工具支持,它帮助开发者根据不同的环境需求做出相应配置。 1. …...
shallowRef和shallowReactive的用法以及使用场景和ref和reactive的区别
Vue3 浅层响应式 API 1. ref vs shallowRef 1.1 基本概念 ref: 深层响应式,会递归地将对象的所有属性转换为响应式shallowRef: 浅层响应式,只有 .value 的改变会触发更新,不会递归转换对象的属性 1.2 使用对比 // ref 示例 const deepRe…...
mantisbt添加修改用户密码
文章目录 问题当前版本安装流程创建用户修改密码老的方式探索阶段 问题 不太好改密码啊。貌似必须要域名要发邮件。公司太穷,看不见的东西不关心,只能改源码了。 当前版本 当前mantisbt版本 2.27 php版本 7.4.3 安装流程 (下面流程不是…...
mysql 学习6 DQL语句,对数据库中的表进行 查询 操作
前期准备数据 重新create 一张表 create table emp(id int comment 编号,workno varchar(10) comment 工号,name varchar(10) comment 姓名,gender char comment 性别,ager tinyint unsigned comment 年龄,idcard char(18) comment 身份证号,workaddress varchar(10) c…...
零售业革命:改变行业的顶级物联网用例
mpro5 产品负责人Ruby Whipp表示,技术进步持续重塑零售业,其中物联网(IoT)正引领这一变革潮流。 研究表明,零售商们正在采用物联网解决方案,以提升运营效率并改善顾客体验。这些技术能够监控运营的各个方面…...
云计算的概念与特点:开启数字化时代的新篇章
在当今数字化时代,云计算(Cloud Computing)已经成为推动技术创新和业务转型的核心力量。无论是大型企业、中小型企业,还是个人用户,云计算都为其提供了高效、灵活和经济的解决方案。本文将深入探讨云计算的概念及其核心特点,帮助读者全面了解这一革命性技术。 © ivw…...
第二十一周:Mask R-CNN
Mask R-CNN 摘要Abstract文章信息研究动机Mask RCNNRoIPool与RoIAlign 双线性插值Mask Branch(FCN)其他细节Mask RCNN损失Mask分支预测 网络搭建创新点与不足总结 摘要 本篇博客介绍了Mask R-CNN,这是一种用于实例分割的模型,能够在目标检测的基础上实现…...
特朗普政府将开展新网络攻击
近日,特朗普政府已表态:减少物理战争,网络战将代替,以实现美国的全球优势。 特朗普也指示美国网络司令部可以在没有总统批准的情况下开展更广泛行动,尤其是应对一些突发事件,这其实成为了后续美国通过网络…...
Android Studio:视图绑定的岁月变迁(2/100)
一、博文导读 本文是基于Android Studio真实项目,通过解析源码了解真实应用场景,写文的视角和读者是同步的,想到看到写到,没有上帝视角。 前期回顾,本文是第二期。 private Unbinder mUnbinder; 只是声明了一个 接口…...
【已解决】黑马点评项目Redis版本替换过程的数据迁移
黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本,美食/KTV的主页能正常返回,但无法显示内容 上次好不容易升到了5.0以上版本,现在又用不了了 Redis 6.2的windo…...
Maven运行任何命令都报错“Internal error: java.lang.ArrayIndexOutOfBoundsException”
今天遇到一个奇怪的问题,在maven工程下运行任何mvn命令都报“Internal error: java.lang.ArrayIndexOutOfBoundsException”错误,具体错误如下: $ mvn install [INFO] Scanning for projects... [ERROR] Internal error: java.lang.ArrayInd…...
电商平台爬虫开发技术分享:多年的实战经验总结
在当今数字化时代,电商平台的数据蕴含着巨大的商业价值。作为一名从事电商平台爬虫开发的工程师,我深知数据抓取的重要性及其技术挑战。经过多年的实践,我积累了一些宝贵的经验,愿意在这里与大家分享,希望能为同行们提…...
大模型训练策略与架构优化实践指南
标题:大模型训练策略与架构优化实践指南 文章信息摘要: 该分析全面探讨了大语言模型训练、架构选择、部署维护等关键环节的优化策略。在训练方面,强调了pre-training、mid-training和post-training的不同定位与目标;在架构选择上…...
DeepSeek-R1 蒸馏模型及如何用 Ollama 在本地运行DeepSeek-R1
在人工智能飞速发展的领域中,大型语言模型(LLMs)的出现可谓是一项重大变革。在这些模型里,DeepSeek - R1 及其蒸馏模型备受瞩目,它们融合了独特的能力与高可用性。今天我们一起聊一下 DeepSeek - R1 蒸馏模型究竟是什么…...
机器学习 ---逻辑回归
逻辑回归是属于机器学习里面的监督学习,它是以回归的思想来解决分类问题的一种非常经典的二分类分类器。由于其训练后的参数有较强的可解释性,在诸多领域中,逻辑回归通常用作 baseline 模型,以方便后期更好的挖掘业务相关信息或提…...
虚幻浏览器插件 UE与JS通信
温馨提示:本节内容需要结合插件Content下的2_Communication和Resources下的sample.html 一起阅读。 1. UE调用JS 1.1 JS脚本实现 该部分共两步: 导入jstote.js脚本实现响应函数并保存到 ue.interface 中 jsfunc 通过json对象传递参数,仅支持函数名小…...
KVM/ARM——基于ARM虚拟化扩展的VMM
1. 前言 ARM架构为了支持虚拟化做了些扩展,称为虚拟化扩展(Virtualization Extensions)。原先为VT-x创建的KVM(Linux-based Kernel Virtual Machine)适配了ARM体系结构,引入了KVM/ARM (the Linux ARM hypervisor)。KVM/ARM没有在hypervisor中引入复杂的…...
池化层Pooling Layer
1. 定义 池化是对特征图进行的一种压缩操作,通过在一个小的局部区域内进行汇总统计,用一个值来代表这个区域的特征信息,常用于卷积神经网络(CNN)中。 2. 作用 提取代表性信息的同时降低特征维度,具有平移…...
为AI聊天工具添加一个知识系统 之63 详细设计 之4:AI操作系统 之2 智能合约
本文要点 要点 AI操作系统处理的是 疑问(信念问题)、缺省(逻辑问题)和异常(不可控因素 ) 而 内核 的三大功能 (资源分配/进程管理/任务调度)以及外围的三类接口( CLI、GUI和表面模型的 运行时…...
代码随想录——二叉树(二)
文章目录 前言二叉树最大深度二叉树的最小深度翻转二叉树对称二叉树完全二叉树的节点个数平衡二叉树二叉树的所有路径左叶子之和找左下角的值路径总和从中序与后序序列构造二叉树最大二叉树合并二叉树二叉搜索树中的搜索验证二叉搜索树二叉搜索树的最小绝对差二叉树中的众数二叉…...