Skip to content

Django 面试题

1. Django 基础

问题:Django 的主要特点是什么?MTV 架构是什么?

答案

Django 主要特点

  • 快速开发:内置 admin、ORM、表单等
  • 安全可靠:内置防护 CSRF、SQL 注入等
  • 可扩展:丰富的第三方应用
  • 文档完善:详尽的官方文档

MTV 架构

M - Model(模型):数据结构和业务逻辑
T - Template(模板):页面展示
V - View(视图):处理请求,返回响应

与 MVC 的区别

  • MVC 的 Controller 在 Django 中是 URLconf + View
  • MTV 的 View 相当于 MVC 的 Controller
  • MTV 的 Template 相当于 MVC 的 View

2. Django 项目结构

问题:Django 项目的标准结构是怎样的?

答案

myproject/
├── manage.py              # 命令行工具
├── myproject/            # 项目配置
│   ├── __init__.py
│   ├── settings.py       # 配置文件
│   ├── urls.py           # 路由配置
│   ├── asgi.py           # ASGI 配置
│   └── wsgi.py           # WSGI 配置
├── myapp/                # 应用
│   ├── __init__.py
│   ├── admin.py          # 后台配置
│   ├── apps.py           # 应用配置
│   ├── models.py         # 模型
│   ├── views.py          # 视图
│   ├── urls.py           # 应用路由
│   ├── forms.py          # 表单
│   ├── tests.py          # 测试
│   └── migrations/       # 迁移文件
├── templates/            # 模板
├── static/               # 静态文件
└── requirements.txt      # 依赖

3. Django ORM

问题:Django ORM 如何使用?有哪些常用操作?

答案

python
# 1. 定义模型
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)
    
    class Meta:
        db_table = 'categories'
        verbose_name = '分类'

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    tags = models.ManyToManyField('Tag')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['title']),
        ]

# 2. 增删改查
# 创建
article = Article.objects.create(title='标题', content='内容')
# 或
article = Article(title='标题', content='内容')
article.save()

# 查询
Article.objects.all()                          # 所有
Article.objects.get(id=1)                      # 单个
Article.objects.filter(title__contains='关键词')  # 过滤
Article.objects.exclude(status='draft')        # 排除
Article.objects.order_by('-created_at')        # 排序

# 更新
Article.objects.filter(id=1).update(title='新标题')
# 或
article.title = '新标题'
article.save()

# 删除
Article.objects.filter(id=1).delete()
# 或
article.delete()

# 3. 关联查询
# 正向查询
article.category.name

# 反向查询
category.article_set.all()
# 或定义 related_name
# category = models.ForeignKey(Category, related_name='articles')
category.articles.all()

# 多对多
tag.articles.all()

# 4. 聚合查询
from django.db.models import Count, Avg, Sum, Max, Min

Article.objects.aggregate(Count('id'))
Article.objects.aggregate(avg_price=Avg('price'))

# 5. 复杂查询
from django.db.models import Q

# OR 查询
Article.objects.filter(Q(title__contains='A') | Q(title__contains='B'))

# AND 查询
Article.objects.filter(Q(title__contains='A') & Q(content__contains='B'))

# 链式查询
Article.objects.filter(status='published').select_related('category').prefetch_related('tags')

4. Django 视图

问题:Django 视图有哪些类型?如何使用?

答案

python
# 1. 函数视图
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, get_object_or_404

def article_list(request):
    articles = Article.objects.all()
    return render(request, 'articles/list.html', {'articles': articles})

def article_detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    return render(request, 'articles/detail.html', {'article': article})

# 2. 类视图
from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView

class ArticleListView(ListView):
    model = Article
    template_name = 'articles/list.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        return Article.objects.filter(status='published')

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'articles/detail.html'

class ArticleCreateView(CreateView):
    model = Article
    fields = ['title', 'content', 'category']
    template_name = 'articles/form.html'
    success_url = '/articles/'

# 3. API 视图(DRF)
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    @action(detail=True, methods=['post'])
    def publish(self, request, pk=None):
        article = self.get_object()
        article.publish()
        return Response({'status': 'published'})

5. Django 中间件

问题:什么是 Django 中间件?如何使用?

答案

python
# 1. 自定义中间件
class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 请求处理前
        print("Before view")
        
        response = self.get_response(request)
        
        # 响应处理后
        print("After view")
        
        return response

# 2. 完整中间件
class FullMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        return self.get_response(request)
    
    def process_view(self, request, view_func, view_args, view_kwargs):
        # 视图调用前
        pass
    
    def process_exception(self, request, exception):
        # 异常处理
        pass
    
    def process_template_response(self, request, response):
        # 模板响应处理
        return response

# 3. 配置中间件
# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'myapp.middleware.SimpleMiddleware',
]

# 4. 实际应用:请求计时
import time

class TimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        start_time = time.time()
        response = self.get_response(request)
        duration = time.time() - start_time
        response['X-Request-Duration'] = str(duration)
        return response

6. Django 认证系统

问题:Django 的认证系统如何使用?

答案

python
# 1. 内置认证
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required

def user_login(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    
    if user is not None:
        login(request, user)
        return redirect('home')
    else:
        return render(request, 'login.html', {'error': 'Invalid credentials'})

@login_required
def protected_view(request):
    return render(request, 'protected.html')

# 2. 自定义用户模型
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    phone = models.CharField(max_length=20, blank=True)
    avatar = models.ImageField(upload_to='avatars/', blank=True)
    
    class Meta:
        db_table = 'users'

# settings.py
AUTH_USER_MODEL = 'myapp.User'

# 3. 权限管理
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin

@permission_required('myapp.change_article')
def edit_article(request, pk):
    pass

class ArticleEditView(PermissionRequiredMixin, UpdateView):
    permission_required = 'myapp.change_article'
    model = Article
    fields = ['title', 'content']

# 4. 组权限
from django.contrib.auth.models import Group, Permission

# 创建组
editors = Group.objects.create(name='Editors')

# 添加权限
permission = Permission.objects.get(codename='change_article')
editors.permissions.add(permission)

# 用户加入组
user.groups.add(editors)

7. Django 信号

问题:什么是 Django 信号?如何使用?

答案

python
# 1. 内置信号
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver

@receiver(post_save, sender=Article)
def article_saved(sender, instance, created, **kwargs):
    if created:
        print(f"Article created: {instance.title}")
    else:
        print(f"Article updated: {instance.title}")

@receiver(pre_delete, sender=Article)
def article_deleted(sender, instance, **kwargs):
    print(f"Article deleted: {instance.title}")

# 2. 自定义信号
from django.dispatch import Signal

# 定义信号
article_published = Signal()

# 发送信号
def publish_article(article):
    article.status = 'published'
    article.save()
    article_published.send(sender=Article, article=article)

# 接收信号
@receiver(article_published)
def notify_subscribers(sender, article, **kwargs):
    print(f"Notifying subscribers about: {article.title}")

# 3. 信号连接方式
# 方式1:装饰器
@receiver(post_save, sender=Article)
def handler(sender, instance, **kwargs):
    pass

# 方式2:手动连接
post_save.connect(handler, sender=Article)

# 方式3:AppConfig
class MyAppConfig(AppConfig):
    def ready(self):
        from . import signals

8. Django 缓存

问题:Django 如何实现缓存?

答案

python
# 1. 配置缓存
# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
    }
}

# 2. 视图缓存
from django.views.decorators.cache import cache_page

@cache_page(60 * 15)  # 缓存15分钟
def article_list(request):
    articles = Article.objects.all()
    return render(request, 'articles/list.html', {'articles': articles})

# 3. 模板缓存
{% load cache %}
{% cache 500 sidebar %}
    <!-- 缓存内容 -->
{% endcache %}

# 4. 低级缓存 API
from django.core.cache import cache

# 设置缓存
cache.set('my_key', 'my_value', timeout=300)

# 获取缓存
value = cache.get('my_key')

# 删除缓存
cache.delete('my_key')

# 5. 缓存整个站点
# settings.py
MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    # ... 其他中间件
    'django.middleware.cache.FetchFromCacheMiddleware',
]

CACHE_MIDDLEWARE_SECONDS = 600
CACHE_MIDDLEWARE_KEY_PREFIX = ''

9. Django 部署

问题:如何部署 Django 项目?

答案

python
# 1. 生产环境配置
# settings.py
DEBUG = False
ALLOWED_HOSTS = ['example.com', 'www.example.com']

# 静态文件
STATIC_ROOT = '/var/www/static/'
STATIC_URL = '/static/'

# 媒体文件
MEDIA_ROOT = '/var/www/media/'
MEDIA_URL = '/media/'

# 数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'USER': 'myuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

# 缓存
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://localhost:6379/1',
    }
}

# 2. 收集静态文件
python manage.py collectstatic

# 3. 迁移数据库
python manage.py migrate

# 4. Gunicorn 配置
# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "sync"
worker_connections = 1000
timeout = 30
keepalive = 2

# 5. Nginx 配置
server {
    listen 80;
    server_name example.com;
    
    location /static/ {
        alias /var/www/static/;
    }
    
    location /media/ {
        alias /var/www/media/;
    }
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# 6. Docker 部署
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

RUN python manage.py collectstatic --noinput

CMD ["gunicorn", "myproject.wsgi:application", "-c", "gunicorn.conf.py"]