第一次接触Django是在2015年,当时我需要为一个教育机构快速搭建一个包含课程管理、学员注册和内容发布功能的平台。面对紧迫的交付期限,Django的"电池内置"理念让我在三天内就完成了基础架构搭建,这让我深刻理解了为什么它被称为Python Web开发的"瑞士军刀"。
Django遵循MTV(Model-Template-View)架构模式,这与传统的MVC略有不同但理念相通。模型(Model)负责数据结构和数据库交互,模板(Template)处理前端展示,视图(View)则是业务逻辑的核心。这种清晰的职责分离让开发者可以快速定位和修改各个功能模块。
提示:Django的MTV模式中,View相当于MVC中的Controller,而Template相当于MVC中的View,这种命名差异经常让初学者困惑。
框架内置的ORM系统让开发者可以用Python类定义数据模型,而无需直接编写SQL语句。例如定义一个简单的博客文章模型:
python复制from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
这段代码不仅定义了数据结构,还自动生成了数据库表,并提供了完整的数据增删改查接口。这种开发效率在需要快速迭代的项目中尤为宝贵。
Flask是一个典型的"微框架",它只提供最基础的路由和模板功能,其他所有组件都需要开发者自行选择和集成。这种灵活性适合小型项目或API服务,但也意味着每个新项目都要重复做出许多架构决策。
我曾用Flask开发过一个简单的天气查询API,确实轻快灵活。但当需求扩展到需要用户认证、后台管理时,就不得不引入Flask-Login、Flask-Admin等扩展,这时发现各扩展间的集成和配置相当耗时。而Django这些功能都是开箱即用的。
FastAPI是近年兴起的新星,专为构建高性能API设计。它采用Python类型提示和异步支持,在纯API开发场景下确实优势明显。去年我参与的一个物联网项目就选择了FastAPI,因为它需要处理大量设备上报数据的实时API。
但FastAPI缺乏Django那种全面的后台管理界面和内置的用户认证系统。当项目需要内容管理功能时,Django的Admin后台可以节省大量开发时间。根据我的经验,如果项目同时需要API和后台管理,常见做法是用Django做主体,再用DRF(Django REST Framework)提供API。
基于多年项目经验,我总结了一个简单的选择框架的决策流程:
Django需要Python 3.6及以上版本。我强烈建议使用pyenv管理多个Python版本,特别是在同时维护多个项目时:
bash复制# 安装pyenv
curl https://pyenv.run | bash
# 安装特定Python版本
pyenv install 3.10.6
# 创建项目专用环境
pyenv virtualenv 3.10.6 myproject-env
使用pip安装最新稳定版Django:
bash复制pip install django
创建新项目时,我习惯添加一个点(.)在当前目录创建,避免多余的嵌套目录:
bash复制django-admin startproject myproject .
这会产生标准的Django项目结构:
code复制myproject/
├── manage.py # 项目管理脚本
└── myproject/ # 项目配置目录
├── __init__.py
├── settings.py # 项目设置
├── urls.py # 根URL配置
└── wsgi.py # WSGI入口
Django项目由多个应用(app)组成,每个应用处理一个特定功能。创建应用:
bash复制python manage.py startapp blog
新创建的blog应用目录包含:
code复制blog/
├── migrations/ # 数据库迁移文件
├── __init__.py
├── admin.py # Admin后台配置
├── apps.py # 应用配置
├── models.py # 数据模型
├── tests.py # 测试
└── views.py # 视图函数
Django的ORM系统是其最强大的功能之一。它允许用Python类定义数据模型,自动转换为数据库表。例如扩展之前的博客模型:
python复制from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
STATUS_CHOICES = [
('draft', '草稿'),
('published', '已发布'),
]
title = models.CharField(max_length=200, verbose_name="标题")
slug = models.SlugField(max_length=250, unique_for_date='publish')
author = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField()
publish = models.DateTimeField(default=timezone.now)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.publish.year,
self.publish.month,
self.publish.day,
self.slug])
这个模型展示了Django ORM的几个关键特性:
Django视图有两种主要编写方式:基于函数的视图(FBV)和基于类的视图(CBV)。对于初学者,FBV更直观:
python复制from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.published.all()
return render(request, 'blog/post/list.html', {'posts': posts})
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request, 'blog/post/detail.html', {'post': post})
而CBV提供了更好的代码复用,特别是对于常见的CRUD操作:
python复制from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
queryset = Post.published.all()
context_object_name = 'posts'
template_name = 'blog/post/list.html'
class PostDetailView(DetailView):
model = Post
context_object_name = 'post'
template_name = 'blog/post/detail.html'
Django模板语言(DTL)设计得既强大又安全,自动处理HTML转义防止XSS攻击。我建议采用以下目录结构:
code复制templates/
├── base.html # 基础模板
└── blog/
└── post/
├── list.html
└── detail.html
基础模板base.html定义通用结构:
html复制<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Blog{% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
子模板继承并扩展基础模板:
html复制{% extends "base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<p class="date">Published {{ post.publish }} by {{ post.author }}</p>
{{ post.content|linebreaks }}
{% endblock %}
Django的Admin后台是其杀手级功能之一。通过简单配置,就能获得完整的数据管理界面。首先创建超级用户:
bash复制python manage.py createsuperuser
然后在admin.py中注册模型:
python复制from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish', 'status')
list_filter = ('status', 'created', 'publish', 'author')
search_fields = ('title', 'content')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'publish'
ordering = ('status', 'publish')
这些配置会生成一个功能完善的管理界面,包含:
Django项目通常部署在Linux服务器上,常用组合是Nginx + Gunicorn。首先安装必要组件:
bash复制# Ubuntu示例
sudo apt update
sudo apt install nginx python3-pip python3-venv
创建生产环境专用的虚拟环境并安装依赖:
bash复制python3 -m venv /opt/myprojectenv
source /opt/myprojectenv/bin/activate
pip install django gunicorn psycopg2-binary
创建Gunicorn服务文件/etc/systemd/system/gunicorn.service:
ini复制[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/project
ExecStart=/opt/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application
[Install]
WantedBy=multi-user.target
启动并启用服务:
bash复制sudo systemctl start gunicorn
sudo systemctl enable gunicorn
创建Nginx配置文件/etc/nginx/sites-available/myproject:
nginx复制server {
listen 80;
server_name yourdomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /path/to/your/project;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
启用配置并重启Nginx:
bash复制sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
Django ORM虽然方便,但可能产生低效查询。使用select_related和prefetch_related优化关联查询:
python复制# 不好的写法:会产生N+1查询问题
posts = Post.objects.all()
for post in posts:
print(post.author.username) # 每次循环都查询数据库
# 好的写法:使用select_related一次性获取关联数据
posts = Post.objects.select_related('author').all()
开发和生产环境的静态文件处理方式不同。在settings.py中配置:
python复制# 开发环境
if DEBUG:
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
else:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
生产环境需要收集静态文件:
bash复制python manage.py collectstatic
Django虽然内置了许多安全功能,但仍需注意:
在settings.py中添加安全配置:
python复制SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
随着项目增长,建议采用更模块化的结构:
code复制myproject/
├── apps/ # 自定义应用
│ ├── blog/
│ └── users/
├── config/ # 项目配置
│ ├── settings/
│ │ ├── base.py
│ │ ├── dev.py
│ │ └── prod.py
│ └── urls.py
├── static/ # 静态文件
├── templates/ # 全局模板
└── manage.py
这种结构通过拆分settings.py为不同环境配置,使项目更易于维护。
基于我教授Django多年的经验,推荐以下学习路线:
基础阶段(1-2周)
中级阶段(2-4周)
高级阶段(1-2月)
专家阶段(持续)
在多年的Django开发中,我总结了几个关键经验:
项目初期规划很重要:花时间设计好数据模型,后期修改成本很高。我曾经在一个项目中因为早期模型设计不当,导致后期不得不进行复杂的数据迁移。
合理使用缓存:对于读多写少的数据,Django的缓存框架能显著提升性能。一个新闻网站项目通过合理使用缓存,QPS从50提升到了500+。
不要过度依赖Admin:虽然Admin后台强大,但复杂业务逻辑最好构建独立的管理界面。曾经因为过度定制Admin导致升级困难。
测试驱动开发:Django内置了完善的测试框架。养成编写测试的习惯能大幅减少生产环境问题。一个统计显示,有良好测试覆盖的项目,生产环境bug减少了70%。
关注安全更新:订阅Django的安全公告,及时应用安全补丁。我曾见证过因为延迟更新导致的安全事故。
Django的强大之处在于它提供了一套完整的解决方案,而不是一堆需要自己组装的零件。它可能不是所有场景的最优解,但当需要快速构建一个功能完整、安全可靠的Web应用时,它仍然是Python生态系统中最成熟的选择。