Appearance
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 response6. 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 signals8. 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"]