用Django搭建第一个Python网站:我的实战经验分享
背景与起因

大家好,我是后端开发工程师小李。入行五年多,从最初的PHP到后来转向Python,再到现在的Go、Node混搭,技术一直在变,但Django始终是我在Python生态中最信赖的Web框架之一。
今天想和大家分享下当初我第一次使用 Django 搭建一个完整网站的过程。虽然已经过去好几年了,但那种“从零开始写出一个能跑的服务”的成就感,至今仍记忆犹新。
当时我们公司接到一个客户的需求,要做一个用于内部资料上传管理的系统。客户对响应速度要求不高,但是希望快速上线,并且团队里有 Python 背景的人。于是,我们决定采用 Django 快速搭建原型。
这篇文章不是那种“hello world级别”的教程,而是基于实际项目的体验来写的,中间踩了不少坑,也总结出了不少经验,希望能给刚入门 Django 的同学一些帮助。
项目背景:为什么选择Django?

我们的项目是一个企业内部文档管理系统,主要功能包括:
- 用户注册登录
- 文档上传(支持PDF、Word)
- 文档分类与标签管理
- 权限控制(不同部门只能查看特定分类文档)
客户需求明确,时间又紧(两个月内要上线),我们团队都是Python出身。这时候 Django 的“电池已包含”特性就显得特别合适:
- 自带admin后台,可以快速进行数据管理
- ORM强大,写数据库逻辑方便
- 用户认证机制成熟
- 社区插件丰富,遇到问题容易找到解决方案
所以最终我们选用了 Django + PostgreSQL + Vue.js 做前后端分离架构。
问题一:从创建项目开始,第一步就卡住了?

还记得刚开始那会儿,执行 django-admin startproject mysite 创建完项目目录后,看着满眼的 .py 文件有点懵圈:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
这些文件到底是干嘛的?settings怎么配置?数据库还没连上怎么办?
解决方案1:先搞清楚项目结构
我花了一个下午把官方文档翻了一遍,结合 Google 上查到的文章,大致明白了这几个核心文件的作用:
- manage.py:命令行工具,运行服务器、迁移数据库等操作都靠它。
- settings.py:全局配置文件,数据库连接信息、第三方应用、静态资源路径都放这里。
- urls.py:URL路由映射,类似前端路由的概念。
- wsgi.py & asgi.py:部署时需要用到,一般初期可以不用管。
为了快速起步,我直接修改了 settings.py 中的数据库部分:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'doc_system',
'USER': 'postgres',
'PASSWORD': 'yourpassword',
'HOST': 'localhost',
'PORT': '5432',
}
}
然后执行 python manage.py migrate 初始化数据库表,看到一堆默认的 auth 表生成,才松了一口气。
小贴士:建议初学者先使用 SQLite 开发,减少配置成本。后期再切换回 Postgres。
问题二:用户系统怎么做?

这个系统的用户权限设计其实不简单,因为涉及部门、角色(比如管理员、普通员工)、以及文档访问控制。如果完全自己实现,工作量不小。
解决方案2:利用Django内置auth模块
Django自带一套完整的用户系统,包括User模型、权限组、令牌等功能。我们可以:
- 使用默认的 User 模型
- 创建新的 Profile 模型扩展字段(如所属部门)
- 利用Group和Permission做权限管理
举个例子,我想给每个用户添加一个“部门”字段:
# models.py
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
# views.py
def user_profile(request):
profile = request.user.profile
return render(request, 'profile.html', {'profile': profile})
当然还要记得在 apps.py 里面注册 app,在 admin.py 注册模型才能在后台管理。
小插曲:有一次我误删了admin账户,整个后台进不去了。还好PostgreSQL中还有记录,手动加回来才发现原来密码是加密存储的。这让我意识到:一定要保护好你的超级用户账号,生产环境更要谨慎管理权限!
问题三:文档上传功能如何实现?
这是整个项目的核心功能之一,需要处理 PDF、Word 文件上传、存储、展示、下载。一开始我以为随便找个Form组件就搞定了,结果发现远远没那么简单。
解决方案3:自定义Model + File Upload 处理
1. 定义文档模型
# models.py
class Document(models.Model):
title = models.CharField(max_length=255)
file = models.FileField(upload_to='documents/%Y/%m/%d/')
category = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE)
tags = models.ManyToManyField('Tag')
created_at = models.DateTimeField(auto_now_add=True)
这里的 upload_to 是指定媒体文件上传路径格式,按年月日分层级,避免单目录文件太多。
2. 设置MEDIA_ROOT和MEDIA_URL
在 settings.py 中添加:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
同时在 urls.py 中加入:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
这样就能通过 /media/xxx.pdf 直接访问上传的文件了。
3. 上传接口设计
我采用了前后端分离的设计思路,前端用Vue.js传文件,后端提供 REST 接口接收并保存:
# views.py
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.views import APIView
class UploadDocument(APIView):
parser_classes = [MultiPartParser, FormParser]
def post(self, request, *args, **kwargs):
file_serializer = DocumentSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4. 遇到的问题及解决
文件太大怎么办?
我们最初测试阶段上传几十MB没问题,结果客户真的传了几百MB的视频!直接超时崩溃。
最终方案:
- 前端用axios设置timeout
- 后端增加Nginx代理限制上传大小(通过client_max_body_size)
- 引入断点续传(虽然最后没上线,但做了技术准备)
安全性问题
我们不允许任意类型的文件上传,尤其是
.php,.exe等。所以在上传前加了一层白名单过滤:def validate_file_extension(value): ext = os.path.splitext(value.name)[1] valid_extensions = ['.pdf', '.docx', '.xlsx'] if not ext.lower() in valid_extensions: raise ValidationError('Unsupported file extension.')在 Model 的 file 字段加上 validators 参数即可。
问题四:性能瓶颈出现——数据库慢得像蜗牛?
上线几个月后,文档数量涨到几万条,首页加载明显变慢。有时候用户刷新页面都要两三秒。
解决方案4:优化数据库查询 + Redis缓存
1. 查询优化:减少N+1查询问题
我们原本在首页显示文档列表的时候,每个文档都要查它的category名称、tags名称。这就导致了一个页面生成需要十几二十次SQL请求。
解决办法是使用 select_related 和 prefetch_related:
Document.objects.select_related('category').prefetch_related('tags')
这可以让Django一次把关联的数据全部拉取过来,大大减少查询次数。
2. 加Redis缓存
我们为文档详情页和首页引入了缓存机制:
from django.core.cache import cache
def get_document_detail(doc_id):
key = f'document_{doc_id}'
doc = cache.get(key)
if not doc:
doc = Document.objects.get(id=doc_id)
cache.set(key, doc, timeout=60*15) # 缓存15分钟
return doc
缓存让整体响应时间下降到了200ms以内,效果立竿见影。

3. 分页优化
当文档列表超过一万条后,翻页变得非常慢。我们启用了游标分页:
Paginator(Document.objects.all(), per_page=20)
或者更高级的,用DRF(Django REST Framework)提供的 CursorPagination,避免 offset 导致的性能下降。
问题五:生产环境怎么部署?
最开始我们用 runserver 本地跑着玩没问题,真要部署到生产服务器上才发现根本不行。我们需要考虑:
- 如何部署?
- 怎么处理静态文件?
- 怎么保证高可用?
- 错误日志去哪看?
解决方案5:Nginx + Gunicorn + Supervisor + Docker
我们最终采用的是:
Client -> Nginx -> Gunicorn -> Django App
同时引入 Supervisor 管理进程,Docker打包镜像。
静态文件管理
Django本身不适合处理静态资源,我们在 production settings 里改成了:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# 收集所有静态文件到STATIC_ROOT
python manage.py collectstatic
Nginx中配置静态目录指向该路径:
location /static/ {
alias /path/to/staticfiles/;
}
日志监控
我们还接入了 Sentry(错误追踪)和 ELK(日志收集),便于定位线上问题。
总结:Django的魅力在于“快”、“稳”、“全”

现在回头看,这个项目算是我们团队转型的第一个正式交付产品。Django确实帮我们节省了大量时间成本,尤其是在前期验证想法、快速迭代方面,展现出了极强的优势。
而且到现在为止,服务稳定运行一年多,没有出过大事故。这也验证了 Django 在中小型项目中的稳定性。
给新手的一些建议
如果你也是刚刚接触 Django,或者准备用它来开发自己的项目,以下是几点我亲身经历过的心得:
✅ 先从简单的项目练手
不要一开始就想着做一个大型平台。你可以先做个博客系统、投票网站,练练 Model、View、Template 的基本功。
✅ 把数据库设计清楚
ORM 再强大,也不能忽视数据库设计。合理的索引、外键关系、范式设计会让你受益终身。
✅ 多使用中间件和服务
像 DRF、Django-REST-Framework、Celery、Channels 这些工具都可以极大提升效率。别重复造轮子。
✅ 部署之前就开始考虑运维
很多人开发完成后才开始研究部署,结果各种报错。应该从开发初期就了解 WSGI、Gunicorn、NGINX 的基础原理。
✅ 多参与社区,少走弯路
Stack Overflow、GitHub Issues、Reddit 和知乎等社区都有很多真实案例可以参考。
结语:Django依然是Python Web开发的首选之一
随着FastAPI的兴起,不少人开始质疑Django是否过时了。但在我看来,Django依然适合中大型业务场景下的快速开发,尤其在复杂度较高、需要完整生态支持的项目中,它依然不可替代。
当然,Django也不是万能的。对于高并发、低延迟的微服务,我们也有其他的选择(如Go、Node、FastAPI)。但如果你正准备做一个传统意义上的Web系统,Django依然值得你深入学习。
希望这篇文章对你有所帮助,也欢迎留言交流你的使用经验!
作者简介:
小李,拥有5年后端开发经验,专注于Python生态,曾主导多个从0到1的Web系统项目落地。目前致力于构建高效稳定的后端架构体系。

评论 0