从零到一:我用 Django 搭建的第一个网站
引言:一个需求催生的尝试

去年公司要做一个内部的知识管理系统,用于整理产品资料、技术文档和项目复盘内容。前端已经决定用 Vue 来开发,但后端选型上大家一时拿不准主意。当时我们团队虽然主要是 Java 栈出身,但也一直在寻找快速构建原型的方式。Python 在数据分析领域的强大生态吸引了不少关注,而 Django 作为一个成熟的 Web 框架,也被列入了候选名单。
作为团队里对 Python 比较熟悉的一员,我就接下了这个任务:用 Django 快速搭出一套基础架构,支撑起整个系统的核心功能。那也是我第一次真正意义上独立完成一个完整的网站项目,过程中踩了不少坑,也积累了很多经验。今天写这篇文章,不是为了展示多么高深的技术,而是想以第一人称的角度,把那些实际遇到的问题、解决的思路以及学到的经验分享出来,希望能帮到刚开始学习 Django 的你。
项目背景与挑战:不只是一个小网站

我们最初的需求很明确:
- 用户可以注册、登录
- 可以上传文档(PDF、Markdown 等格式)
- 文档支持分类、标签管理
- 支持全文搜索(模糊匹配 + 关键词)
- 基础权限控制:管理员、普通用户角色区分
听起来似乎不复杂,但真实开发中才发现问题远没那么简单。首先是时间压力 —— 上线周期只有三周;其次,我们还要考虑后期扩展性,毕竟谁也不能保证这个知识库未来不会承载更多业务场景。
更现实的是,团队成员大多是 Java 出身,我对 Django 的了解其实还停留在“会看懂示例代码”的阶段,并没有真正开发过大型项目。怎么在有限的时间内搭建起结构清晰、易于维护的系统,成了我面临的首要问题。
为什么选择 Django?


在综合考量了几个方案之后,我最终选择了 Django。原因有以下几点:
- 开发效率高:自带 ORM 和 Admin 后台,很多重复的工作可以直接跳过。
- 安全性好:内置 CSRF、SQL 注入防护等机制,避免新手犯低级错误。
- 成熟稳定:社区活跃,文档齐全,遇到问题基本上都能找到答案。
- 适合中小型项目:Django 的整体设计非常适合快速迭代,尤其适合初创或 MVP 场景。
另外,在部署方面,Django 对主流服务器(比如 Nginx + Gunicorn)的支持也很完善,运维成本不高,这对我们这样一个非全栈 Python 团队来说非常重要。
技术方案设计:先画蓝图再动手
架构设计
我们的整体架构采用前后端分离模式:
Vue.js (前端) <-> REST API (Django) <-> PostgreSQL / Redis
前端负责渲染页面、调用接口;后端通过 DRF(Django REST framework)提供标准化接口;数据库使用 PostgreSQL,Redis 用于缓存搜索结果和 Token 管理。
数据库设计
数据模型围绕“用户-文档-分类-标签”四个核心实体展开:
- 用户表:继承 Django 内置 User 模型,添加头像、手机号字段
- 文档表:存储文件路径、元数据、标签关系、所属分类等信息
- 分类表:树状结构,支持多级分类(使用 django-mptt 实现)
- 标签表:扁平结构,与文档形成多对多关联
其中文档与标签的关系是典型的 ManyToManyField,这里需要注意中间表的设计是否合理,是否支持额外属性(例如权重)。
接口设计原则
RESTful 是基本原则,同时遵循一些实用主义做法:
- 返回统一结构:
{ "code": 0, "data": {}, "message": "" } - 使用 JWT 做认证鉴权(借助 djangorestframework-simplejwt)
- 分页统一为 offset/limit 形式
- 所有增删改操作返回完整对象,避免客户端二次查询
代码实践:关键模块实现
接下来我会贴一些关键代码片段,帮助你理解如何落地这些设计。
初始化项目结构
django-admin startproject knowledge_base
cd knowledge_base
python manage.py startapp documents users
推荐每个功能模块单独建 app,方便解耦和后期迁移。我们在主项目的 settings.py 中配置 app:
INSTALLED_APPS = [
'rest_framework',
'rest_framework_simplejwt',
'drf_yasg', # 接口文档工具
'users.apps.UsersConfig',
'documents.apps.DocumentsConfig',
]
用户模型自定义
为了让用户支持头像、手机号等字段,我们需要继承默认的 User 模型:
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
avatar = models.ImageField(upload_to='avatars/')
phone = models.CharField(max_length=20)
别忘了在 settings.py 中指定:
AUTH_USER_MODEL = 'users.CustomUser'
文档模型定义
from django.db import models
from users.models import CustomUser
class Document(models.Model):
name = models.CharField("标题", max_length=200)
file = models.FileField(upload_to="documents/%Y/%m/%d")
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
tags = models.ManyToManyField('Tag')
upload_by = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
create_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
序列化器(DRF)
from rest_framework import serializers
from documents.models import Document
class DocumentSerializer(serializers.ModelSerializer):
class Meta:
model = Document
fields = "__all__"
视图逻辑(基于 GenericAPIView)
from rest_framework.generics import ListCreateAPIView
from documents.models import Document
from .serializers import DocumentSerializer
class DocumentList(ListCreateAPIView):
queryset = Document.objects.all()
serializer_class = DocumentSerializer
URL 路由配置
from django.urls import path
from documents.views import DocumentList
urlpatterns = [
path('documents/', DocumentList.as_view()),
]
整个流程走下来你会发现,Django+DRF 的组合真的非常高效,尤其是在 CRUD 场景下几乎不用手动写 SQL。
遇到的坑和解决方案
下面是一些我在实际开发中遇到的真实问题及解决方式:
1. 大文件上传超时
初期我们用普通的 FileField 存储文档,但由于有些 PDF 文件较大(超过 100MB),前端上传时常出现超时。我们最终采用了两种方式优化:
- 客户端分片上传(Vue + Dropzone.js 实现)
- 后端使用
chunked_upload插件处理断点续传
pip install drf-chunked-upload
然后配置路由即可,这部分插件封装得非常好,集成简单。
2. 全文搜索性能差
一开始我们用简单的 contains 做关键词搜索,但在数据量达到几千条后明显变慢。后来引入了 Elasticsearch 做搜索引擎:
- 利用
django-elasticsearch-dsl同步数据到 ES - 单独建立索引类:
from django_elasticsearch_dsl.documents import Document
from documents.models import Document as DocModel
@registry.register_document
class DocDocument(Document):
class Index:
name = 'documents'
class Django:
model = DocModel
fields = [
'name',
'content', # 文档内容
]
搜索接口就变成了直接调用 ES,性能提升非常明显。
3. JWT Token 刷新逻辑混乱
起初我们用 DRF SimpleJWT 默认的刷新机制,但由于前端需要定时刷新 Token,导致部分请求失败。我们后来统一用 Axios 封装了一层拦截器来自动刷新:
axios.interceptors.response.use(
response => response,
async error => {
if (error.response.status === 401) {
const refreshToken = localStorage.getItem('refresh');
// 请求刷新Token
const res = await refreshTokenApi(refreshToken);
localStorage.setItem('access', res.access);
// 重新发送原请求
return axios(error.config);
}
return Promise.reject(error);
}
)
这样用户体验更好,也能减少因 Token 过期带来的请求失败。
效果总结:系统上线后的表现
项目最终如期上线,运行至今已将近一年。目前支撑了公司内部的几十个部门使用,每天活跃用户约 200 多人,文档总量突破 8000 篇。
从运维角度看,Django 表现得很稳定。部署环境是 Ubuntu + Nginx + Gunicorn,通过 supervisor 管理进程。内存占用控制得也不错,一台 4GB 的机器就能轻松应付日常请求。日志、错误监控我们用的是 Sentry,排查问题也方便。
我的一些建议和注意事项
如果你正准备开始自己的第一个 Django 项目,以下几点是我亲身体会后的建议:
1. 结构清晰比代码短更重要
Django 的灵活性有时候反而容易让人陷入“随意组织目录”的误区。我的建议是:
- 功能模块按功能拆分为不同 app
- 每个 app 内部保持一致性结构(models、views、urls、serializers 等)
- 不要怕文件多,合理的拆分反而更容易维护
2. ORM 虽好,但别滥用
Django ORM 确实非常强大,但有些复杂的查询还是建议用 raw 或者用数据库函数。记得定期用 query.count() 查看执行次数,避免产生 N+1 查询问题。
3. 认证鉴权早做规划
一开始就应该确定认证机制,不要等到后期再去补。JWT 是一个很好的选择,但也要注意 Token 的管理和刷新策略。
4. 接口文档一定要做
不要小看接口文档的作用。我们项目一开始就引入了 Swagger UI(drf-yasg),这对前后端协作起到了很大帮助。即使你是单兵作战,也建议坚持写注释文档,后期维护的时候你会感谢自己。
5. 性能优化要趁早
虽然 Django 本身性能不错,但在数据量增长后,如果不做任何优化,还是会慢慢“卡起来”。建议:
- 数据库加合适的索引
- 查询尽量 select_related/prefetch_related
- 缓存常用数据(Redis)
- 耗时操作异步化(Celery)
6. 学会看日志、查文档
Django 的报错信息通常都很详细,遇到问题不妨先看看日志。官方文档和 Stack Overflow 是解决问题的最好资源。此外,GitHub 上的 Issues 区域往往藏着意想不到的答案。
结语:每一个大工程都是从一行代码开始的
回过头来看,当初那个紧张兮兮地照着教程一步步来的我,现在也慢慢有了自己的开发习惯和判断力。Django 确实是一个值得投入学习的框架,它不仅帮你节省时间,更是在潜移默化中让你养成良好的工程思维。
希望这篇实战经验分享能给你带来一些启发和信心。无论你现在处于什么水平,只要你肯动手写,坚持查文档、问问题、解决问题,相信你很快也能写出属于自己的第一个 Django 网站。
愿你在技术路上越走越稳,码出精彩人生!

评论 0