Appearance
Flask 面试题
1. Flask 基础
问题:Flask 的主要特点是什么?与 Django 有什么区别?
答案:
Flask 主要特点:
- 轻量级:核心简单,扩展丰富
- 灵活:没有强制项目结构
- 微框架:只提供核心功能,其他通过扩展实现
- 易于上手:学习曲线平缓
Flask vs Django:
| 特性 | Flask | Django |
|---|---|---|
| 架构 | 微框架 | 全功能框架 |
| 灵活性 | 高 | 中 |
| 学习曲线 | 平缓 | 陡峭 |
| 内置功能 | 少 | 多 |
| 数据库 | 可选 | ORM 内置 |
| 管理后台 | 无内置 | 内置 admin |
| 适用场景 | 小型项目、API | 大型项目、企业应用 |
2. Flask 应用结构
问题:Flask 项目的标准结构是怎样的?
答案:
myproject/
├── app/ # 应用包
│ ├── __init__.py # 应用工厂
│ ├── models.py # 数据模型
│ ├── routes.py # 路由
│ ├── forms.py # 表单
│ ├── templates/ # 模板
│ │ └── index.html
│ └── static/ # 静态文件
│ ├── css/
│ ├── js/
│ └── images/
├── migrations/ # 数据库迁移
├── tests/ # 测试
├── config.py # 配置
├── requirements.txt # 依赖
├── run.py # 启动脚本
└── wsgi.py # WSGI 入口python
# 应用工厂模式
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
db = SQLAlchemy()
login_manager = LoginManager()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
db.init_app(app)
login_manager.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')
return app3. Flask 路由和视图
问题:Flask 中如何定义路由和视图函数?
答案:
python
from flask import Flask, request, jsonify, render_template, redirect, url_for
app = Flask(__name__)
# 1. 基本路由
@app.route('/')
def index():
return 'Hello, Flask!'
# 2. 动态路由
@app.route('/user/<username>')
def show_user(username):
return f'User: {username}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'Post: {post_id}'
# 3. HTTP 方法
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# 验证逻辑
return redirect(url_for('index'))
return render_template('login.html')
# 4. 请求对象
@app.route('/api/data', methods=['POST'])
def get_data():
# 获取 JSON 数据
data = request.get_json()
# 获取表单数据
name = request.form.get('name')
# 获取查询参数
page = request.args.get('page', 1, type=int)
# 获取文件
file = request.files['file']
# 获取请求头
auth_header = request.headers.get('Authorization')
return jsonify({'status': 'success'})
# 5. 响应对象
from flask import make_response
@app.route('/custom-response')
def custom_response():
response = make_response('Custom response', 200)
response.headers['X-Custom-Header'] = 'Value'
response.set_cookie('session', 'abc123')
return response
# 6. 蓝图
from flask import Blueprint
auth = Blueprint('auth', __name__)
@auth.route('/login')
def login():
return 'Login page'
@auth.route('/register')
def register():
return 'Register page'
# 注册蓝图
app.register_blueprint(auth, url_prefix='/auth')4. Flask-SQLAlchemy
问题:Flask 中如何使用 SQLAlchemy 进行数据库操作?
答案:
python
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# 1. 定义模型
class User(db.Model):
__tablename__ = 'users'
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)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f'<User {self.username}>'
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
# 2. 数据库操作
# 创建表
with app.app_context():
db.create_all()
# 增
new_user = User(username='alice', email='alice@example.com')
db.session.add(new_user)
db.session.commit()
# 查
user = User.query.filter_by(username='alice').first()
users = User.query.all()
user = User.query.get(1) # 根据主键查询
# 改
user.email = 'new_email@example.com'
db.session.commit()
# 删
db.session.delete(user)
db.session.commit()
# 3. 复杂查询
from sqlalchemy import or_, and_
# 过滤
users = User.query.filter(User.username.like('%alice%')).all()
users = User.query.filter(or_(User.username == 'alice', User.username == 'bob')).all()
# 排序
users = User.query.order_by(User.username.desc()).all()
# 分页
pagination = User.query.paginate(page=1, per_page=10, error_out=False)
users = pagination.items
total = pagination.total
pages = pagination.pages
# 4. 关联查询
# 一对多
user = User.query.get(1)
posts = user.posts # 获取用户的所有文章
# 预加载
users = User.query.options(db.joinedload(User.posts)).all()5. Flask 表单处理
问题:Flask 中如何处理表单?
答案:
python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Email, Length, EqualTo
# 1. 定义表单
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[
DataRequired(),
Length(min=4, max=20)
])
email = StringField('Email', validators=[
DataRequired(),
Email()
])
password = PasswordField('Password', validators=[
DataRequired(),
Length(min=6)
])
confirm_password = PasswordField('Confirm Password', validators=[
DataRequired(),
EqualTo('password')
])
submit = SubmitField('Sign Up')
# 2. 视图中使用
from flask import render_template, redirect, url_for, flash
@app.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('Registration successful!', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
# 3. 模板中使用
# register.html
"""
<form method="POST" action="">
{{ form.hidden_tag() }}
<div>
{{ form.username.label }}
{{ form.username(class="form-control") }}
{% if form.username.errors %}
{% for error in form.username.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
{% endif %}
</div>
<div>
{{ form.submit(class="btn btn-primary") }}
</div>
</form>
"""
# 4. 文件上传
from flask_wtf.file import FileField, FileAllowed
class UploadForm(FlaskForm):
file = FileField('File', validators=[
FileAllowed(['jpg', 'png'], 'Images only!')
])
submit = SubmitField('Upload')
@app.route('/upload', methods=['POST'])
def upload():
form = UploadForm()
if form.validate_on_submit():
file = form.file.data
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return 'File uploaded successfully'6. Flask 用户认证
问题:Flask 中如何实现用户认证?
答案:
python
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
# 1. 用户模型
class User(UserMixin, db.Model):
__tablename__ = 'users'
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)
password_hash = db.Column(db.String(128))
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)
# 2. 用户加载回调
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# 3. 登录视图
from flask import Blueprint
auth = Blueprint('auth', __name__)
@auth.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
return redirect(next_page) if next_page else redirect(url_for('main.index'))
flash('Invalid username or password', 'danger')
return render_template('auth/login.html', form=form)
# 4. 登出视图
@auth.route('/logout')
@login_required
def logout():
logout_user()
flash('You have been logged out.', 'info')
return redirect(url_for('main.index'))
# 5. 保护路由
@main.route('/profile')
@login_required
def profile():
return render_template('profile.html', user=current_user)
# 6. 注册视图
@auth.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
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('Registration successful!', 'success')
return redirect(url_for('auth.login'))
return render_template('auth/register.html', form=form)7. Flask RESTful API
问题:如何使用 Flask 构建 RESTful API?
答案:
python
from flask import Flask, jsonify, request
from flask_restful import Api, Resource
from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt_identity
app = Flask(__name__)
api = Api(app)
app.config['JWT_SECRET_KEY'] = 'your-secret-key'
jwt = JWTManager(app)
# 1. 基本 API
class HelloWorld(Resource):
def get(self):
return {'message': 'Hello, World!'}
api.add_resource(HelloWorld, '/')
# 2. CRUD API
class UserAPI(Resource):
@jwt_required()
def get(self, user_id):
user = User.query.get_or_404(user_id)
return {
'id': user.id,
'username': user.username,
'email': user.email
}
@jwt_required()
def put(self, user_id):
user = User.query.get_or_404(user_id)
data = request.get_json()
user.username = data.get('username', user.username)
user.email = data.get('email', user.email)
db.session.commit()
return {'message': 'User updated successfully'}
@jwt_required()
def delete(self, user_id):
user = User.query.get_or_404(user_id)
db.session.delete(user)
db.session.commit()
return {'message': 'User deleted successfully'}
class UserListAPI(Resource):
def get(self):
users = User.query.all()
return {
'users': [
{'id': u.id, 'username': u.username, 'email': u.email}
for u in users
]
}
def post(self):
data = request.get_json()
user = User(
username=data['username'],
email=data['email']
)
user.set_password(data['password'])
db.session.add(user)
db.session.commit()
return {'message': 'User created successfully'}, 201
api.add_resource(UserAPI, '/api/users/<int:user_id>')
api.add_resource(UserListAPI, '/api/users')
# 3. JWT 认证
@app.route('/api/login', methods=['POST'])
def login():
username = request.json.get('username')
password = request.json.get('password')
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
access_token = create_access_token(identity=user.id)
return {'access_token': access_token}
return {'message': 'Invalid credentials'}, 401
# 4. 错误处理
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Not found'}), 404
@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return jsonify({'error': 'Internal server error'}), 500
# 5. 请求验证
from marshmallow import Schema, fields, validate
class UserSchema(Schema):
username = fields.Str(required=True, validate=validate.Length(min=4))
email = fields.Email(required=True)
password = fields.Str(required=True, validate=validate.Length(min=6))
user_schema = UserSchema()
@app.route('/api/users', methods=['POST'])
def create_user():
json_data = request.get_json()
try:
data = user_schema.load(json_data)
except ValidationError as err:
return jsonify({'errors': err.messages}), 400
# 创建用户...8. Flask 扩展
问题:Flask 有哪些常用扩展?
答案:
python
# 1. Flask-SQLAlchemy - ORM
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
# 2. Flask-Login - 用户认证
from flask_login import LoginManager
login_manager = LoginManager(app)
# 3. Flask-WTF - 表单处理
from flask_wtf import FlaskForm
# 4. Flask-Mail - 邮件发送
from flask_mail import Mail, Message
mail = Mail(app)
@app.route('/send-mail')
def send_mail():
msg = Message(
'Hello',
sender='from@example.com',
recipients=['to@example.com']
)
msg.body = 'This is a test email'
mail.send(msg)
return 'Email sent'
# 5. Flask-Caching - 缓存
from flask_caching import Cache
cache = Cache(app, config={
'CACHE_TYPE': 'RedisCache',
'CACHE_REDIS_URL': 'redis://localhost:6379/0'
})
@app.route('/cached')
@cache.cached(timeout=50)
def cached_view():
return 'This is cached'
# 6. Flask-Migrate - 数据库迁移
from flask_migrate import Migrate
migrate = Migrate(app, db)
# 命令
# flask db init
# flask db migrate -m "Initial migration"
# flask db upgrade
# 7. Flask-Admin - 管理后台
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
admin = Admin(app)
admin.add_view(ModelView(User, db.session))
# 8. Flask-RESTful - REST API
from flask_restful import Api, Resource
api = Api(app)
# 9. Flask-JWT-Extended - JWT 认证
from flask_jwt_extended import JWTManager
jwt = JWTManager(app)
# 10. Flask-CORS - 跨域
from flask_cors import CORS
CORS(app)
# 11. Flask-Limiter - 限流
from flask_limiter import Limiter
limiter = Limiter(
app,
key_func=lambda: request.remote_addr
)
@app.route('/limited')
@limiter.limit('5 per minute')
def limited():
return 'This is rate limited'
# 12. Flask-Assets - 静态文件管理
from flask_assets import Environment, Bundle
assets = Environment(app)
js = Bundle('js/main.js', filters='jsmin', output='gen/packed.js')
assets.register('js_all', js)9. Flask 测试
问题:如何测试 Flask 应用?
答案:
python
import unittest
from app import create_app, db
from app.models import User
class TestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
self.client = self.app.test_client()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_home_page(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'Hello', response.data)
def test_login(self):
# 创建测试用户
u = User(username='test', email='test@example.com')
u.set_password('password')
db.session.add(u)
db.session.commit()
# 测试登录
response = self.client.post('/auth/login', data={
'username': 'test',
'password': 'password'
}, follow_redirects=True)
self.assertEqual(response.status_code, 200)
def test_api(self):
# 测试 API
response = self.client.get('/api/users')
self.assertEqual(response.status_code, 200)
json_data = response.get_json()
self.assertIsInstance(json_data['users'], list)
# 使用 pytest
import pytest
@pytest.fixture
def app():
app = create_app('testing')
with app.app_context():
db.create_all()
yield app
db.drop_all()
@pytest.fixture
def client(app):
return app.test_client()
def test_home_page(client):
response = client.get('/')
assert response.status_code == 200
assert b'Hello' in response.data10. Flask 部署
问题:如何部署 Flask 应用?
答案:
python
# 1. 生产环境配置
import os
class ProductionConfig:
DEBUG = False
TESTING = False
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
# 2. Gunicorn 配置
# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "sync"
worker_connections = 1000
timeout = 30
keepalive = 2
errorlog = "-"
accesslog = "-"
# 3. Docker 部署
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
ENV FLASK_APP=run.py
ENV FLASK_ENV=production
EXPOSE 8000
CMD ["gunicorn", "-c", "gunicorn.conf.py", "run:app"]
# 4. Nginx 配置
server {
listen 80;
server_name example.com;
location /static {
alias /var/www/app/static;
}
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;
}
}
# 5. 环境变量管理
# .env
FLASK_ENV=production
SECRET_KEY=your-secret-key
DATABASE_URL=postgresql://user:password@localhost/dbname
REDIS_URL=redis://localhost:6379/0
# python-dotenv
from dotenv import load_dotenv
load_dotenv()