models.py
从零开始,用Django搭建我的第一个Python网站
大家好,我是张工,在一家互联网公司负责后端开发。最近我在参与一个内部项目时,尝试使用 Django 构建了一个简单的 Python 网站。这是我在工作中首次深度接触 Django 框架,从一开始的懵懂到后来逐渐上手,整个过程充满了挑战和收获。
今天我想分享一下这段经历——包括我为什么选择 Django、在开发过程中遇到的实际问题、以及如何一步步把它搭起来的过程。也许你也是刚入行或者打算进入 Python Web 开发领域的新手,希望这篇基于真实工作场景的经验分享能帮你在学习 Django 的路上少走一些弯路。
起因:为什么我要选 Django?
事情要回到上个月的一次需求评审会上。我们团队接到了一个任务——为公司内部搭建一个轻量级的员工信息管理平台(Intranet 工具),主要功能是:
- 员工基本信息展示
- 部门结构可视化
- 快速查找和筛选
- 可导出为 CSV 报表
这个平台的目标用户是公司内部人员,访问频率不算高,数据敏感性也不大,属于“够用就行”的类型。作为负责人,我需要快速交付一个原型,并且方便后续扩展。
考虑到时间和人力成本,我希望找一个既能快速开发、又能支撑一定规模应用的框架。PHP?太老了;Flask?虽灵活但很多轮子都得自己造;Node.js?当时刚好不在我的知识体系优先级里。于是我想起了之前略有耳闻的 Django —— 它内置了许多开箱即用的功能模块,比如 Admin 后台、ORM、模板系统、用户认证等等,非常适合这种中等规模的管理系统。
最终决定:试一试 Django!
实践第一步:初始化项目与目录结构规划
先来个热身环节吧,创建你的第一个 Django 项目。我一般习惯用虚拟环境隔离依赖,所以第一步就是:
python3 -m venv env
source env/bin/activate
pip install django
django-admin startproject employee_manager .
执行完之后会生成如下的基础目录结构:
employee_manager/
├── manage.py
└── employee_manager/
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
接下来,我创建了一个 core 应用来组织核心业务逻辑:
python manage.py startapp core
并将其添加到 settings.py 中的 INSTALLED_APPS 列表里。
这时候我已经意识到一个潜在的问题:虽然 Django 提供了强大的 ORM 支持,但如果一开始就随意地定义模型,后期修改起来可能很麻烦。尤其是当数据库结构变动频繁的时候,迁移(Migration)操作如果不加注意,很容易出现数据丢失或混乱的情况。
所以我决定先梳理清楚业务模型之间的关系,再着手写 models。
数据库设计:简单却不能随便
这个系统的主要模型有三个:
- Employee(员工)
- Department(部门)
- Position(职位)
它们之间大致是这样的关系:
- 一名员工只能属于一个部门,但每个部门可以有多名员工。
- 每位员工有一个对应的职位,但一个职位可以被多个员工持有。
- 部门可以嵌套父子关系(例如 IT 部下面分为前端组、后端组)。
于是我在 models.py 中设计如下模型结构(部分字段省略):
from django.db import models
class Department(models.Model):
name = models.CharField(max_length=100)
parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)
def __str__(self):
return self.name
class Position(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
class Employee(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(unique=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
position = models.ForeignKey(Position, on_delete=models.SET_NULL, null=True)

def __str__(self):
return f"{self.first_name} {self.last_name}"
看起来挺简单对吧?但在实际开发中,我发现一个问题:如果我们直接用 Django 自带的 Admin 界面来管理这些数据,前端交互体验其实并不理想,特别是当你需要同时编辑多层嵌套的部门信息时。
怎么办呢?我选择了自定义 Admin 页面,并使用 TabularInline 来改善关联编辑体验:
# admin.py
from django.contrib import admin
from .models import Department, Employee, Position
class EmployeeInline(admin.TabularInline):
model = Employee
extra = 1
@admin.register(Department)
class DepartmentAdmin(admin.ModelAdmin):
inlines = [EmployeeInline]
admin.site.register(Position)
这样就可以在一个页面上查看某个部门的所有员工了,效率提升了不少。
接口设计与性能优化:别忽视 RESTful 风格
除了后台管理,我还需要提供 API 接口给前端调用。因为后面可能会接入其他微服务系统,所以接口设计一定要规范、可拓展。
我使用的是 Django 自带的视图函数 + Django REST framework 插件。
安装 DRF:
pip install djangorestframework
然后在 urls.py 中配置路由,定义视图函数:
# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Employee
from .serializers import EmployeeSerializer
@api_view(['GET'])
def get_employees(request):
employees = Employee.objects.all()
serializer = EmployeeSerializer(employees, many=True)
return Response(serializer.data)
配合 serializers.py 定义序列化逻辑:
# serializers.py
from rest_framework import serializers
from .models import Employee
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = '__all__'
但这里我遇到了一个小坑:随着数据量增加,全表查询变得缓慢。尤其是当员工数量超过 5000 条之后,GET /api/employees 接口响应时间明显延长。
分析发现:
- 一次性返回所有员工会导致内存占用过高;
- 查询未建立索引;
- 大量字段未按需加载。
于是我对接口做了以下几项优化:
- 分页机制
引入分页器:
from rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
@api_view(['GET'])
def get_employees(request):
queryset = Employee.objects.all().select_related('department', 'position')
paginator = StandardResultsSetPagination()
result_page = paginator.paginate_queryset(queryset, request)
serializer = EmployeeSerializer(result_page, many=True)
return paginator.get_paginated_response(serializer.data)
这样既降低了单次请求的数据压力,也提升了接口稳定性。
- 数据库查询优化
通过 .select_related() 和 .prefetch_related() 减少 N+1 查询问题,并结合 Django Debug Toolbar 查看实际 SQL 执行情况。
- 建立索引
对于经常用于搜索的字段(如 email、first_name),在模型中指定数据库索引:
email = models.EmailField(unique=True, db_index=True)
这大大提高了 WHERE 查询的速度。
踩过的那些坑:生产部署中的真实教训
开发完成后,我开始着手部署。由于这是一个公司内网项目,我决定使用 Nginx + Gunicorn + PostgreSQL 搭建一个轻量级的部署环境。
第一次上线踩雷:“静态文件找不到”
在本地测试没问题,但部署到服务器后,CSS 和 JS 文件全都加载失败。
查日志发现:
- Django 默认不会处理静态资源;
- 使用
runserver本地测试的时候,它自己会处理静态文件; - 一旦换到 Gunicorn+Nginx,必须手动配置静态资源路径。
解决方法:
在
settings.py中添加:STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')运行收集命令:
python manage.py collectstatic --noinput在 Nginx 配置中设置:
location /static/ { alias /path/to/staticfiles/; }
生产环境配置注意事项
关闭 DEBUG 模式:
DEBUG = False ALLOWED_HOSTS = ['your.domain.com']不然线上报错信息全暴露出去,有安全风险。
正确设置 SECRET_KEY:
不要提交到版本控制里。建议放在环境变量中读取:
import os SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'fallback-secret-key-if-none')使用 Gunicorn 启动服务:
我常用的启动命令(带进程数):
gunicorn --workers 3 employee_manager.wsgi:application日志监控:
部署后最好启用日志记录,方便追踪错误:
LOGGING = { 'version': 1, 'handlers': { 'file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': '/path/to/debug.log', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'DEBUG', 'propagate': True, }, }, }
最终效果与个人心得
经过一周多的折腾,项目顺利上线,目前运行稳定,访问速度良好。前端同事反馈说接口清晰、文档完整,整体协作非常顺畅。
从这次实战中,我总结了几个实用经验:
先画模型,再写代码:
- 模型的设计决定了数据的可维护性和扩展性;
- 如果一开始没理清,后期改模型牵一发动全身。
不要小看分页的重要性:
- 即使现在只有几百条数据,未来数据增长起来就会卡顿;
- 分页 + 缓存能解决大多数性能瓶颈。
接口设计要规范:
- 遵循 RESTful 标准,命名清晰;
- 返回格式统一(状态码 + data + msg);
- 尽早对接 Swagger 文档,提升协作效率。
调试工具是好伙伴:
- Django Debug Toolbar;
- Django extensions(如 shell_plus);
- 测试驱动开发(TDD)也能帮助你写出更健壮的代码。
部署前做好准备:
- 静态资源、权限、数据库连接都要检查;
- 线上环境永远不要保留 DEBUG=True;
- 日志是故障排查的第一线武器。
结语:别怕复杂,慢慢积累经验
说实话,第一次独立完成一个完整的 Django 项目并不是一件轻松的事,中间经历了各种调试、踩坑和重构。但正是这些看似琐碎的小事,让我逐步建立了对整个系统架构的理解,也让我对 Python Web 开发有了更深的兴趣。
如果你也是刚入门 Django,不用着急追求什么“完美架构”或“最佳实践”。先把项目跑起来,再去思考怎么做得更好,这才是最实在的成长方式。
最后送大家一句话:“慢一点没关系,坚持走下去才是关键。”
如果你在尝试的过程中遇到任何问题,欢迎留言交流!我们一起成长。

评论 0