Skip to content

Flask 面试题

1. Flask 基础

问题:Flask 的主要特点是什么?与 Django 有什么区别?

答案

Flask 主要特点

  • 轻量级:核心简单,扩展丰富
  • 灵活:没有强制项目结构
  • 微框架:只提供核心功能,其他通过扩展实现
  • 易于上手:学习曲线平缓

Flask vs Django

特性FlaskDjango
架构微框架全功能框架
灵活性
学习曲线平缓陡峭
内置功能
数据库可选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 app

3. 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.data

10. 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()