Django入门教程:搭建你的第一个Python网站
上周五晚上十点半,我瘫在工位上盯着屏幕上一堆 500 Internal Server Error,内心已经把产品经理祖宗十八代问候了个遍。事情是这样的:我们小厂最近接了个政府外包项目,要求两周内上线一个简单的数据展示平台。前端兄弟甩锅说后端接口没给,测试妹子疯狂@我问什么时候能测,运维大哥直接在群里艾特:“再不上线就别回家了。”
更要命的是,这活儿原本是另一个同事负责的,结果他周一提了离职(没错,又是金三银四跑路潮),领导二话不说把需求塞给我:“你不是会Python吗?Django搞一下呗。” 我心里一万个草泥马奔腾而过——我平时主要用Go写微服务啊!但看着工资条和北京房租,还是默默打开了PyCharm。
说起来有点惭愧,虽然在GitHub上Star了一堆Django项目,但真正动手写还是头一回。今天这篇博客,就是记录我这个“Go转Django”菜鸟如何在deadline前把网站跑起来的血泪史。顺便也回答下最近面试被问爆的面试题:“Django和Flask有什么区别?”——现在我可以拍着胸脯说:都TM是坑,但Django的坑有官方填土包!
为什么选Django?不都是Python Web框架吗?
先说背景:我们公司后端技术栈主要是Go + Gin,为啥这次不用熟悉的工具?原因很现实:
- 时间紧:Django自带Admin、ORM、用户认证,能快速搭出可演示的原型
- 需求简单:就是CRUD+数据展示,不需要高并发(政府项目嘛,流量能有多大)
- 团队技能:实习生会Python,后期维护有人接手
📌 面试题延伸:面试官问Django vs Flask,千万别只说“Django大而全,Flask轻量”。要结合场景!比如我说:“如果要做内部管理系统,Django省50%开发时间;如果是API网关或中间件,Flask更灵活。” 这才是加分项。
环境搭建:别让第一步就劝退你
先吐槽下Python环境管理——比Go复杂多了!Go只要装个二进制文件就行,Python还得搞虚拟环境。我用的是venv(别跟我提conda,公司服务器没权限装):
# 创建项目目录
mkdir gov-data-platform && cd gov-data-platform
# 创建虚拟环境(Python 3.8+)
python3 -m venv .venv
# 激活环境(Mac/Linux)
source .venv/bin/activate
# Windows用:.venv\Scripts\activate
# 安装Django(指定版本避免踩新坑)
pip install Django==4.2.7
💡 生产经验:一定要固定版本!去年双11期间,有个同事没锁Django版本,半夜线上报
FieldDoesNotExist,原因是Django 4.2改了模型字段校验逻辑... 自此我们所有requirements.txt都带精确版本号。
创建第一个应用:Hello World都不简单
Django的“项目-应用”结构一开始让我很懵(Go里直接main.go走起)。按官方文档敲命令:
# 创建项目
django-admin startproject gov_platform .
# 创建应用(注意最后的点!很多人漏掉导致路径错乱)
python manage.py startapp data_show
目录结构长这样:
gov_platform/
├── manage.py
├── gov_platform/ # 项目配置
│ ├── __init__.py
│ ├── settings.py # ⚠️重点!数据库、中间件都在这
│ ├── urls.py
│ └── wsgi.py
└── data_show/ # 你的业务代码
├── migrations/
├── models.py # 数据库表定义
├── views.py # 处理请求
└── ...
这时候我犯了个低级错误:把业务逻辑写在gov_platform/views.py里。结果第二天Code Review被组长骂:“你这是要把settings.py变成单体应用吗?” 正确姿势是每个功能拆成独立app,方便后期解耦。
数据库设计:别学我用SQLite上线
因为赶时间,我本地用SQLite快速开发(Django默认配置)。models.py写了三个表:
# data_show/models.py
from django.db import models
class Department(models.Model):
name = models.CharField(max_length=100, unique=True)
code = models.CharField(max_length=20, unique=True)
class DataRecord(models.Model):
dept = models.ForeignKey(Department, on_delete=models.CASCADE)
value = models.DecimalField(max_digits=10, decimal_places=2)
report_date = models.DateField()
class Meta:
# 联合唯一索引!防重复上报
unique_together = ('dept', 'report_date')
🚨 血泪教训:本地跑得好好的,部署到测试环境时运维说:“生产用MySQL,你这decimal字段精度不够!” 原来SQLite对decimal支持不严格,MySQL直接报错。永远用生产同款数据库开发!现在我们团队强制要求Docker Compose启动MySQL容器开发。
迁移命令很简单:
python manage.py makemigrations
python manage.py migrate
但要注意:makemigrations生成的文件要提交到Git!否则其他开发者拉代码后数据库结构对不上,又是一场灾难。
视图与模板:告别JSON,拥抱HTML
作为Go开发者,我习惯返回JSON(毕竟前后端分离是常态)。但这次甲方要求“传统页面”,得用Django模板。views.py这么写:
# data_show/views.py
from django.shortcuts import render
from .models import Department, DataRecord
def dashboard(request):
# 预加载部门数据(避免N+1查询!)
records = DataRecord.objects.select_related('dept').all()
return render(request, 'dashboard.html', {'records': records})
模板文件放在data_show/templates/dashboard.html:
<!-- 注意:Django模板语法和Go的text/template完全不同 -->
{% for record in records %}
<div>
{{ record.dept.name }}: {{ record.value }}
</div>
{% endfor %}
💡 性能提示:
select_related相当于SQL的JOIN,避免循环查数据库。我第一次没加,测试环境100条数据就慢得像蜗牛——这要是Go里早用GORM预加载了,但在Django里得主动调用。
静态文件:CSS/JS加载失败的真相
页面样式乱成狗,F12一看404。原来Django对静态文件有特殊处理!需要在settings.py配置:
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / "static", # 开发时静态文件目录
]
STATIC_ROOT = BASE_DIR / "staticfiles" # collectstatic输出目录
然后执行:
# 收集所有app的静态文件到STATIC_ROOT
python manage.py collectstatic
🤦♂️ 踩坑实录:运维部署时忘了跑collectstatic,线上CSS全挂。从此我们CI流程加了这一步,还写了检查脚本——小厂没SRE,只能自己当运维。
部署上线:从localhost到公网
终于到了最刺激的环节!我们用Nginx + Gunicorn(别用Django自带server,那是玩具)。
1. 安装Gunicorn
pip install gunicorn
2. 启动命令
# --bind 绑定内网IP,--workers 根据CPU核数调整
gunicorn --bind 0.0.0.0:8000 gov_platform.wsgi:application
3. Nginx反向代理配置
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态文件直接由Nginx处理(更快!)
location /static/ {
alias /path/to/staticfiles/;
}
}
🔒 安全提醒:别把DEBUG=True放线上!我们曾因DEBUG=True导致数据库密码泄露(Django错误页会打印环境变量)。现在部署脚本第一行就是
sed -i 's/DEBUG = True/DEBUG = False/' settings.py。
对比Go:Django的取舍之道
折腾完这个项目,我对Django有了新认识。做个简单对比:
| 维度 | Django (Python) | Gin (Go) |
|---|---|---|
| 开发速度 | ⭐⭐⭐⭐⭐ (Admin/ORM开箱即用) | ⭐⭐ (需手写大量胶水代码) |
| 性能 | ⭐⭐ (Python解释型语言瓶颈) | ⭐⭐⭐⭐⭐ (编译型,高并发利器) |
| 学习曲线 | ⭐⭐⭐ (约定大于配置) | ⭐⭐ (简洁但需理解中间件) |
| 生态 | ⭐⭐⭐⭐ (Web领域无敌) | ⭐⭐⭐ (微服务生态强) |
说白了:Django适合快速交付业务系统,Go适合构建高性能基础设施。就像我们公司——内部管理后台用Django,用户交易核心用Go。
写在最后:代码人生的另一种可能
凌晨三点,当我看到政府验收邮件里写着“系统运行稳定”时,突然有点感慨。以前总觉得写Go才叫“正经程序员”,Django不过是脚本玩具。但这次经历让我明白:技术没有高低贵贱,解决问题才是王道。
就像上周团建,领导说:“别总想着重构,先把需求做完。” 是啊,在小厂生存,既要能写高并发架构,也要能撸起袖子搭个Django站。毕竟——
面试题可以背,但线上Bug得亲手修;
Go可以吹性能,但甲方爸爸要的是明天上线。
如果你也在被 deadline 追着跑,不妨试试Django。它可能不够酷,但足够稳。就像北京早高峰的地铁——挤是挤了点,但总能把你送到目的地。
P.S. 本文代码已脱敏上传GitHub(私信我拿链接),包含Dockerfile和Nginx配置。下次跳槽面试被问Django,至少能说出“我在生产环境用过”而不是“看过教程”。毕竟在这个卷成麻花的行业,真实的项目经验,永远比八股文值钱。
(完)
作者:某小厂后端,坐标北京,通勤1h,正在用Django救火的同时偷偷学Rust。技术博客更新不定期,但保证全是踩坑实录。

评论 0