Django初体验:一个成都小厂后端的Python建站实战手记
上周五晚上十点,办公室只剩下我和隔壁组那个总爱穿拖鞋的运维小哥。我盯着屏幕上一行报错信息发呆:“TemplateDoesNotExist at /”,心里默默问候了Django祖宗十八代——这都第几次了?明明照着文档一步步来的啊!
这事得从头说起。我是成都一家十几人小公司的后端开发,独立负责一条电商业务线。平时主要用Go写微服务,但最近产品经理突然提了个需求:要做个内部运营后台,用来管理用户标签和营销活动。工期两周,下周就要给老板演示。
“用Go写个Web界面?那不得累死?”我心里嘀咕。虽然我们主系统都是Go + Gin,但搞个完整的后台管理界面,光是模板渲染、表单处理、用户认证这些轮子就得造半天。更别说我还得兼顾线上系统的稳定性——去年双11期间那个Redis缓存穿透事故还历历在目,当时真的想砸电脑。
思来想去,决定试试Django。为啥?因为听说它“自带干粮”,开箱即用。而且最近刷求职网站发现,好多JD都写着“熟悉Django优先”,面试题里也经常出现Django相关的问题。作为一个有上进心(且想跳槽)的小厂程序员,这不正好是个学习机会?
为什么不是Flask或者继续用Go?
说实话,一开始我也纠结过。毕竟Go是我吃饭的家伙,而且Gin框架轻量又快。但仔细一想,在这种需要快速出原型的场景下,Go的“显式优于隐式”反而成了负担。
| 框架 | 开发速度 | 学习曲线 | 内置功能 | 适合场景 |
|---|---|---|---|---|
| Django | ⚡⚡⚡⚡⚡ | 中等 | 超全(ORM、Admin、Auth等) | 快速原型、全栈应用 |
| Flask | ⚡⚡⚡ | 低 | 基础,靠扩展 | 微服务、API接口 |
| Go+Gin | ⚡⚡ | 高 | 几乎没有 | 高性能后端服务 |
你看,我要的是一个带用户登录、数据展示、表单提交的完整Web应用,而不是单纯的API服务。Django的Admin后台简直就是为这种需求量身定制的——自动生成CRUD界面,连权限控制都有。
再说Flask,虽然简单灵活,但要实现同样的功能,我得自己集成SQLAlchemy、Flask-Login、WTForms等等,配置起来比写业务逻辑还费时间。在这个deadline压顶的时候,显然不是最优选择。
至于Go... 咱也不是不能写,但用echo或gin配合html/template的话,每个页面都要手动处理模板变量、CSRF防护、session管理。两天时间可能就耗在这些基础功能上了,老板怕是要把我祭天。
从零开始:三十分钟搭个能跑的网站
废话不多说,直接开干。首先确保你装了Python 3.8+(我们生产环境用的是3.9),然后:
# 创建虚拟环境(别偷懒,这是好习惯)
python -m venv django-env
source django-env/bin/activate # Linux/Mac
# django-env\Scripts\activate # Windows
# 安装Django
pip install django
# 创建项目
django-admin startproject ops_backend
cd ops_backend
# 创建应用(Django里叫app)
python manage.py startapp marketing
到这里,一个最基本的Django项目结构就出来了。说实话,第一次看到这么多文件夹和配置文件时我有点懵——这比Go的一个main.go复杂多了。但慢慢就发现,这种“约定优于配置”的设计其实很贴心。
关键配置都在settings.py里,比如数据库默认用SQLite(开发够用),静态文件路径、时区设置等等。我们小公司暂时没那么多讲究,先用默认配置跑起来再说。
# settings.py 关键配置示例
INSTALLED_APPS = [
'django.contrib.admin', # 后台管理
'django.contrib.auth', # 用户认证
'django.contrib.contenttypes',
'django.contrib.sessions', # session支持
'django.contrib.messages',
'django.contrib.staticfiles',
'marketing', # 我们自己的app
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
LANGUAGE_CODE = 'zh-hans' # 中文支持
TIME_ZONE = 'Asia/Shanghai'
接下来定义数据模型。我们的需求很简单:用户标签管理和营销活动配置。
# marketing/models.py
from django.db import models
from django.contrib.auth.models import User
class UserTag(models.Model):
name = models.CharField('标签名称', max_length=50, unique=True)
description = models.TextField('描述', blank=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField('创建时间', auto_now_add=True)
class Meta:
verbose_name = '用户标签'
verbose_name_plural = '用户标签'
class MarketingCampaign(models.Model):
title = models.CharField('活动标题', max_length=100)
target_tags = models.ManyToManyField(UserTag, verbose_name='目标标签')
start_time = models.DateTimeField('开始时间')
end_time = models.DateTimeField('结束时间')
is_active = models.BooleanField('是否启用', default=True)
class Meta:
verbose_name = '营销活动'
verbose_name_plural = '营销活动'
写完模型,执行数据库迁移:
python manage.py makemigrations
python manage.py migrate
这时候神奇的事情发生了——Django不仅创建了数据库表,还自动给我生成了超级用户管理界面!运行开发服务器:
python manage.py createsuperuser # 创建管理员账号
python manage.py runserver
访问 http://127.0.0.1:8000/admin,输入刚才创建的账号密码,哇塞!所有模型的增删改查界面都自动生成了,连中文显示都完美支持。这效率,比我用Go手撸三天还快。
踩坑实录:那些让我想砸键盘的时刻
当然,事情不可能一帆风顺。第一个大坑就是静态文件。本地开发时一切正常,但当我尝试部署到测试环境时,CSS和JS全部404。
原来Django在DEBUG=False时不会自动提供静态文件服务,需要单独配置。我们小公司没专门的运维,只能自己搞定Nginx配置:
# nginx.conf 片段
location /static/ {
alias /path/to/your/project/staticfiles/;
}
同时在settings.py里加上:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
然后执行 python manage.py collectstatic 收集所有静态文件。这个过程折腾了我整整一个下午,主要是对Django的静态文件机制理解不够深入。
第二个坑是时区问题。数据库里存的时间总是比本地时间少8小时。后来才发现Django默认使用UTC时区,而我们在settings.py里只改了TIME_ZONE,忘了告诉数据库也用本地时区。解决方案是在数据库连接配置里加上:
DATABASES = {
'default': {
# ...其他配置
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
'TIME_ZONE': 'Asia/Shanghai', # 显式指定
}
}
还有一次,我在写表单验证时,因为没理解Django的CSRF机制,POST请求一直返回403。后来才知道要在模板里加上 {% csrf_token %},或者在view函数上加 @csrf_exempt 装饰器(不推荐)。这些细节看似简单,但对新手来说真的很劝退。
和Go生态的对比思考
作为一个日常写Go的开发者,用Django的过程中一直在做对比。最明显的感受是:Go追求显式和可控,Django追求约定和便利。
比如数据库操作:
- Go中你需要自己写SQL或者用GORM这样的ORM,每一步都很明确
- Django的ORM则高度抽象,
.filter().exclude().order_by()链式调用很爽,但有时候生成的SQL不够优化
再比如错误处理:
- Go强制你处理每个error,虽然啰嗦但不容易遗漏
- Django遇到异常直接抛500页面,开发时方便,但生产环境需要额外配置日志监控
不过话说回来,这两种哲学没有绝对的优劣。就像我们公司的技术栈:核心交易系统用Go保证高性能和稳定性,内部工具用Django快速迭代。综合来看,选择合适的工具比盲目追求技术先进性更重要。
这也让我想起最近面试时被问到的一个问题:“你们为什么在某些场景选择Python而不是Go?” 现在我可以自信地回答:开发效率和团队能力匹配度才是关键考量。不是所有场景都需要高并发,有时候快速交付比极致性能更有价值。
给想学Django的求职者的建议
如果你正在准备求职,特别是想进一些用Python的技术团队,Django确实是必学技能。但别只是照着教程敲代码,要深入理解它的设计思想:
- MTV架构模式:Model-Template-View,对应MVC中的Model-View-Controller
- 中间件机制:类似Go的middleware,但更强大,可以处理请求/响应的各个阶段
- 信号系统:解耦组件间的通知机制,比硬编码回调优雅得多
最重要的是,动手做一个完整的项目。哪怕只是简单的博客系统,也要走完从需求分析、数据库设计、API开发到部署上线的全流程。我在成都这边参加技术meetup时,很多面试官都说:“看一个人会不会Django,不用问概念,直接让他现场改个bug就知道了。”
顺便吐槽一句,我们公司最近招人,看到简历写“精通Django”的候选人,一问连QuerySet的惰性求值都不清楚,真是让人哭笑不得。技术这东西,真的要沉下心来学。
最后的碎碎念
现在这个运营后台已经上线一周了,产品经理居然没提新需求(奇迹!),老板还夸界面专业。虽然我知道背后是Django Admin的功劳,但不妨碍我小小得意一下。
在成都这座生活节奏舒服的城市,能用合适的技术快速解决问题,下班还能去太古里喝杯咖啡,感觉人生达到了巅峰。当然,如果哪天想挑战更高薪的岗位,这些积累的经验也会成为跳槽的底气。
所以啊,别管外面吹什么Go多么牛、Rust多么快,能解决实际问题的技术就是好技术。Django或许不是最性感的框架,但在特定场景下,它真的香。
对了,如果你也在小厂挣扎求生,或者正准备学习Django,欢迎在评论区交流。说不定下次meetup我们能在IFS楼下偶遇,一起吐槽产品经理呢!
(完)
后记:写这篇文章的时候,我又收到了产品经理的新消息:“那个后台能不能加个数据导出Excel的功能?” 唉,打工人的一天,从Django开始,到Django结束。不过这次我有经验了,pip install django-import-export,十分钟搞定,稳得很!

评论 0