```html
欢迎访问kaoacca.cn - 专注Python后端技术分享与面试指导

Django 面试题全解析

深入理解 Django 面试题 背后的设计哲学,从源码级解析到高并发场景实战,助你构建扎实的后端知识体系。

Django 基础核心考点

在 Django 面试题 中,基础概念往往是考察的第一步。面试官通常希望了解候选人对 MTV 模式、WSGI 接口以及请求生命周期的理解深度。

1.1 WSGI 与 ASGI 的区别

WSGI (Web Server Gateway Interface) 是 Python Web 应用与 Web 服务器之间的标准接口。Django 传统上基于 WSGI,它是同步的,意味着每个请求必须等待前一个请求处理完毕才能开始。然而,随着 WebSocket 和异步编程的兴起,ASGI (Asynchronous Server Gateway Interface) 应运而生。ASGI 支持异步 I/O,允许 Django 处理长连接和并发请求,这在现代 Django 面试题 中越来越重要。

WSGI 特点

同步阻塞、标准接口、兼容性好、适合传统 CRUD 业务。

ASGI 特点

异步非阻塞、支持 WebSocket、高性能、适合实时通信场景。

1.2 Django 请求生命周期

理解请求从发送到响应的完整流程是 Django 面试题 中的高频考点。流程如下:

  1. 路由分发: URLconf 匹配 URL,找到对应的 View。
  2. 中间件处理: 请求经过请求中间件(如 CsrfViewMiddleware)。
  3. 视图执行: View 函数或类被调用,处理业务逻辑。
  4. ORM 操作: 如有数据库操作,执行 SQL 查询。
  5. 模板渲染: 数据传入模板,生成 HTML。
  6. 响应返回: 经过响应中间件,返回给客户端。

ORM 与数据库深度解析

ORM (Object-Relational Mapping) 是 Django 的核心组件之一。在 Django 面试题 中,关于 N+1 问题、查询优化和事务处理的问题层出不穷。

2.1 解决 N+1 查询问题

N+1 问题是 Django ORM 中最常见的性能陷阱。当查询一个主对象列表时,如果每个主对象都关联了一个外键,且没有预先加载,Django 会为每个主对象单独发起一次数据库查询。

❌ 错误示例
✅ 优化方案
books = Book.objects.all()
for book in books:
    print(book.author.name)  # 每次循环都执行一次 SQL,导致 N+1 问题
# 使用 select_related (针对 ForeignKey, OneToOneField)
books = Book.objects.select_related('author').all()
for book in books:
    print(book.author.name)  # 只有一次 SQL 查询,通过 JOIN 实现
# 使用 prefetch_related (针对 ManyToManyField, Reverse ForeignKey)
books = Book.objects.prefetch_related('tags').all()
for book in books:
    print(list(book.tags.all()))

2.2 事务管理

在 Django 面试题 中,数据一致性至关重要。Django 提供了 `transaction.atomic()` 上下文管理器来确保操作的原子性。如果块内发生异常,所有更改将回滚。

from django.db import transaction
def transfer_money(user_from, user_to, amount):
    with transaction.atomic():
        user_from.balance -= amount
        user_from.save()
        user_to.balance += amount
        user_to.save()
        # 如果上面任何一步出错,整个事务回滚

中间件机制详解

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级、低级别的“插件”系统,用于全局修改 Django 的输入或输出。在 Django 面试题 中,自定义中间件是考察点之一。

3.1 中间件执行流程

请求阶段 (Request)

请求到达服务器,依次经过 MIDDLEWARE 列表中定义的中间件的 process_request 方法。如果某个中间件返回了 HttpResponse,则后续中间件及 View 将不再执行,直接进入响应阶段。

视图阶段 (View)

View 函数被调用,执行业务逻辑,返回 HttpResponse 对象。

响应阶段 (Response)

响应对象依次经过中间件的 process_response 方法(顺序与 request 相反)。最后返回给客户端。

3.2 自定义中间件示例

以下是一个简单的中间件,用于记录请求日志:

import logging
logger = logging.getLogger(__name__)
class RequestLogMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        # 请求前处理
        logger.info(f"Request started: {request.path}")
        response = self.get_response(request)
        # 响应后处理
        logger.info(f"Request finished: {request.path}, Status: {response.status_code}")
        return response

缓存策略与性能优化

性能优化是 Django 面试题 中区分初级与高级开发者的关键。Django 提供了多级缓存机制,包括内存缓存、文件缓存、数据库缓存和 Memcached/Redis 缓存。

4.1 缓存后端选择

缓存后端 速度 持久性 适用场景
LocMemCache 极快 无 单进程开发环境
FileBasedCache 慢 有 无外部依赖的简单场景
Memcached/Redis 快 无 (可配置) 生产环境高并发

4.2 缓存颗粒度

在 Django 面试题 中,面试官常问:“你应该缓存什么?”

  • 页面缓存: 使用 @page_cache 装饰器或中间件,缓存整个 HTML 响应。适合变化不频繁的内容。
  • 视图缓存: 使用 @cache_page 装饰器,缓存视图返回的 HttpResponse。适合动态生成但数据更新不频繁的页面。
  • 模板片段缓存: 使用 {% load cache %} 和 {% cache %} 标签,缓存模板中的特定部分。这是最灵活的策略。
  • 数据缓存: 使用 cache.set() 和 cache.get() 直接操作 Python 对象。适合复杂查询结果的重用。

高阶实战与源码剖析

对于资深职位的 Django 面试题,往往涉及源码级理解和高并发场景下的解决方案。

5.1 Django 信号量 (Signals) 的利弊

信号量提供了松耦合的组件间通信机制,如 post_save、pre_delete。然而,在 Django 面试题 中,许多面试官对信号量持保留态度,原因如下:

  1. 调试困难: 信号的处理逻辑分散在不同文件中,难以追踪。
  2. 性能开销: 在批量操作中,如果信号处理逻辑复杂,可能导致性能下降。
  3. 隐式依赖: 代码行为变得不直观,增加维护成本。

建议: 仅在确实需要解耦的场景下使用信号量,否则优先考虑直接在 View 或 Model 方法中处理逻辑。

5.2 异步任务处理

Django 本身是同步的,但在 Django 面试题 中,异步任务处理是必考题。通常结合 Celery + Redis/RabbitMQ 实现。Celery 将耗时任务(如发送邮件、图像处理)放入消息队列,由 Worker 异步执行,从而释放 Web 服务器的资源。

from celery import shared_task
@shared_task
def send_welcome_email(user_id):
    user = User.objects.get(id=user_id)
    # 发送逻辑
    pass
```
斌知网
蜀ICP备2026017620号-5