flask 开发的个人笔记
本博客仅作为笔记,不做教学,教程可以看大佬这的flask教程。
环境
虚拟环境
创建虚拟环境
Windows $ python -m venv env
Linux 或 macOS $ python3 -m venv env
激活虚拟环境
Windows $ env\Scripts\activate
如果在 Windows 中使用 Git Bash,则是 . env/Scripts/activate
Linux 或 macOS $ . env/bin/activate
退出虚拟环境
$ deactivate
flask
视图函数
# 导入Flask库
from flask import Flask
# 创建一个Flask应用实例
app = Flask(__name__)
# 定义一个路由,当用户访问应用的根URL(例如:http://localhost:5000/)时,将触发此函数
@app.route('/')
def hello():
# 返回一个简单的字符串,将在浏览器中显示
return 'Welcome to My Watchlist!'
启动程序
flask run
url_for()的使用
当我有这么一个视图函数时。
@app.route('/user/<username>')
def user_profile(username):
return f"Hello, {username}!"
可以通过url_for()来定位到该函数的URL,然后执行视图函数。
url = url_for('user_profile', username='JohnDoe')
环境设置
- 自动导入系统环境变量的 python-dotenv:
(env) $ pip install python-dotenv
- 在新创建的 .flaskenv 文件里,我们写入一行 FLASK_ENV=development,将环境变量 FLASK_ENV 的值设为 development,以便开启调试模式:
# .flaskenv 文件 FLASK_ENV=development
模板
模板的使用方法
通用模板示例
htmlCopy code<!-- h1标签显示用户的个人主页标题,其中的变量username将被替换为实际值 -->
<h1>{{ username }}的个人主页</h1>
<!-- 使用Jinja2的条件语句判断变量bio是否存在(非空),缩进只是为了可读性,不是必须的 -->
{% if bio %}
<!-- 如果bio变量存在(非空),则在一个<p>标签中显示bio的内容 -->
<p>{{ bio }}</p>
{% else %}
<!-- 如果bio变量不存在(为空),则显示一条默认消息 -->
<p>自我介绍为空。</p>
{% endif %} <!-- 大部分Jinja2语句都需要声明关闭,使用{% endif %}关闭if语句 -->
在这个模板中:
- 使用{{ username }}插入变量username的值。在渲染模板时,需要传递一个包含username键的字典,以提供实际的值。{{ }}语法用于在HTML中输出变量。
- 使用{% if bio %}和{% endif %}创建一个条件语句,判断变量bio是否存在(非空)。{% %}语法用于包含控制结构,如条件语句、循环等。
过滤器
举例{{ 变量|过滤器 }}
具体看这
渲染模板
from flask import Flask, render_template
# ...
@app.route('/')
def index():
return render_template('index.html', name=name, movies=movies)
静态文件
url_for()指向静态文件
固定为以下格式
url_for('static', filename='images/avatar.png
-
- url_for函数在这里用于生成一个指向静态文件(如图片、CSS、JavaScript等)的URL。
- url_for函数的第一个参数'static'告诉Flask你要生成一个静态文件的URL。
- 第二个关键字参数filename用于指定静态文件的路径。注意,这里的参数名应该是filename,而不是name。
- 将filename更改为name可能导致不正确的URL生成,从而导致图片无法显示。所以,当在模板中使用url_for()调用本地图片时,后续参数名不能随意更改。确保使用正确的参数名filename来指定静态文件的路径。
数据库
重新看大佬教程吧
模板优化
模板上下文处理函数
对于多个模板内都需要使用的变量,我们可以使用 app.context_processor 装饰器注册一个模板上下文处理函数,如下所示:
@app.context_processor
def inject_user(): # 函数名可以随意修改
user = User.query.first()
return dict(user=user) # 需要返回字典,等同于 return {'user': user}
这个函数返回的变量(以字典键值对的形式)将会统一注入到每一个模板的上下文环境中,因此可以直接在模板中使用。
模板继承
{% extends 'base.html' %}
{% block content %}
<p>{{ movies|length }} Titles</p>
<ul class="movie-list">
{% for movie in movies %}
<li>{{ movie.title }} - {{ movie.year }}
<span class="float-right">
<a class="imdb" href="https://www.imdb.com/find?q={{ movie.title }}" target="_blank" title="Find this movie on IMDb">IMDb</a>
</span>
</li>
{% endfor %}
</ul>
<img alt="Walking Totoro" class="totoro" src="{{ url_for('static', filename='images/totoro.gif') }}" title="to~to~ro~">
{% endblock %}
表单
- 表单示例
<form method="post"> <!-- 指定提交方法为 POST -->
<label for="name">名字</label>
<input type="text" name="name" id="name"><br> <!-- 文本输入框 -->
<label for="occupation">职业</label>
<input type="text" name="occupation" id="occupation"><br> <!-- 文本输入框 -->
<input type="submit" name="submit" value="登录"> <!-- 提交按钮 -->
</form>
- 表单的注意事项
- 在 <form> 标签里使用 method 属性将提交表单数据的 HTTP 请求方法指定为 POST。如果不指定,则会默认使用 GET 方法,这会将表单数据通过 URL 提交,容易导致数据泄露,而且不适用于包含大量数据的情况。
- <input> 元素必须要指定 name 属性,否则无法提交数据,在服务器端,我们也需要通过这个 name 属性值来获取对应字段的数据。
- 表单的运行逻辑
- 从几个<input>中获取数据
- 通过<input type="submit">提供的按钮,提交数据。
- 以 post 方式,同时携带着数据访问 URL ,此时就可以通过传来的数据进行数据处理了。
- flash 消息的使用
- 传入消息内容
flash('Item Created.')
- 在模板中获取提示消息并显示
<!-- 插入到页面标题上方 --> {% for message in get_flashed_messages() %} <div class="alert">{{ message }}</div> {% endfor %} <h2>...</h2>
- 传入消息内容
用户认证
密码保护(散列值生成、验证)
from werkzeug.security import generate_password_hash, check_password_hash
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
username = db.Column(db.String(20)) # 用户名
password_hash = db.Column(db.String(128)) # 密码散列值
def set_password(self, password): # 用来设置密码的方法,接受密码作为参数
self.password_hash = generate_password_hash(password) # 将生成的密码保持到对应字段
def validate_password(self, password): # 用于验证密码的方法,接受密码作为参数
return check_password_hash(self.password_hash, password) # 返回布尔值
认证保护
视图保护
对于不允许未登录用户访问的视图,只需要为视图函数附加一个 login_required 装饰器就可以将未登录用户拒之门外。比如:
from flask_login import LoginManager
login_manager = LoginManager(app) # 实例化扩展类
login_manager.login_view = 'login' # 用户认证保护的重定向视图函数
# ...
@app.route('/movie/delete/<int:movie_id>', methods=['POST'])
@login_required # 登录保护
def delete(movie_id):
movie = Movie.query.get_or_404(movie_id)
db.session.delete(movie)
db.session.commit()
flash('Item deleted.')
return redirect(url_for('index'))
添加了这个装饰器后,如果未登录的用户访问对应的 URL,Flask-Login 会把用户重定向到登录页面。
模板内容保护
在模板渲染时,会先判断当前用户的登录状态(current_user.is_authenticated)。如果用户没有登录(current_user.is_authenticated 返回 False),就不会渲染表单部分的 HTML 代码,即上面代码块中 {% if ... %} 和 {% endif %} 之间的代码。比如:
<!-- 在模板中可以直接使用 current_user 变量 -->
{% if current_user.is_authenticated %}
<form method="post">
Name <input type="text" name="title" autocomplete="off" required>
Year <input type="text" name="year" autocomplete="off" required>
<input class="btn" type="submit" name="submit" value="Add">
</form>
{% endif %}
测试
有亿点长,感觉我还没学到家,还是看大佬吧。