Django入门教程:搭建你的第一个Python网站(一个刚跳槽程序员的踩坑实录)
上周五晚上十点半,我瘫在工位上盯着屏幕上不断报错的Docker容器,耳机里放着Lo-fi Hip Hop,脑子里却全是“早知道不跳槽了”。没错,我现在就处在那种典型的“新公司迷茫期”——入职才两个月,项目deadline压得喘不过气,团队用的技术栈又和我之前主攻的Springboot生态差了十万八千里。更离谱的是,产品经理昨天突然说:“我们要做一个区块链浏览器的前端展示页”,然后转头问我:“你会Django吗?”
我?我上一次写Python还是在研究生课程作业里跑神经网络……但为了保住饭碗(以及那点可怜的年终奖),我硬着头皮接了下来。
于是,就有了这篇《Django入门教程》,与其说是教学,不如说是我的血泪踩坑日记。如果你也像我一样,刚从Java后端(比如Springboot)转战Python世界,或者正考虑跳槽到一家用Django的公司,那这篇文章可能会让你少走几个通宵的弯路。
为什么是Django?不是Flask?也不是FastAPI?
说实话,一开始我也疑惑:现在不是都在吹FastAPI吗?异步、高性能、自动生成OpenAPI文档,多香啊!但现实很骨感——我们团队的老大是个“稳字当头”派,坚持认为Django的“全栈集成”更适合快速交付MVP(Minimum Viable Product)。而且,他原话是:“区块链数据展示又不是高并发交易系统,别整那些花里胡哨的。”
好吧,我懂了。Django = Python界的Springboot,自带ORM、Admin后台、用户认证、模板引擎,开箱即用。对于需要快速搭个管理后台或数据展示页的场景,确实比手搓Flask省事太多。
环境搭建:第一个坑就差点劝退
我本地开发机是Mac,习惯用pyenv管理Python版本。先装个Django:
pip install django
结果一运行django-admin startproject myblockchain_site,终端直接报错:
Command 'django-admin' not found
???不是刚装了吗?后来才发现,我的虚拟环境没激活!作为一个从Java转来的老手,习惯了IDEA自动配置classpath,结果在Python世界里被PATH变量狠狠教育了一顿。
踩坑提示:务必确认你在正确的virtualenv里!可以用
which python和which pip检查路径是否一致。
接着,我兴冲冲地python manage.py runserver,页面打开——403 Forbidden。查了半天,原来是Django 4.x默认启用了CSRF_TRUSTED_ORIGINS,而我的本地host不在白名单里。解决方案是在settings.py里加一行:
CSRF_TRUSTED_ORIGINS = ['http://localhost:8000', 'http://127.0.0.1:8000']
这种“安全优先”的设计我很欣赏,但对新手真的不友好。相比之下,Springboot启动一个REST API,连CORS都不用配(除非你主动加Security)。
数据库设计:从区块链结构到Django Model
我们的需求很简单:展示最近100个以太坊区块的基本信息(高度、时间戳、交易数等)。我本来想直接用JSONField存整个区块数据,但DBA(我们公司居然还有专职DBA!)严肃警告我:“别把PostgreSQL当MongoDB用。”
于是老老实实用传统关系型建模:
# models.py
from django.db import models
class Block(models.Model):
number = models.BigIntegerField(unique=True, help_text="区块高度")
timestamp = models.DateTimeField()
transaction_count = models.IntegerField(default=0)
hash = models.CharField(max_length=66, unique=True) # 0x + 64 hex chars
parent_hash = models.CharField(max_length=66)
class Meta:
ordering = ['-number'] # 默认按区块高度倒序
indexes = [
models.Index(fields=['number']),
models.Index(fields=['timestamp']),
]
这里有个小细节:区块高度必须设为unique,否则重复插入会炸。我在测试时就因为没加这个约束,导致本地数据库里塞了5条同一个区块的数据,前端显示乱成一锅粥。
另外,别忘了运行迁移命令:
python manage.py makemigrations
python manage.py migrate
这让我想起Springboot的Flyway/Liquibase,虽然Django的migration机制没那么强大,但对于小型项目完全够用。
接口设计:RESTful?还是直接模板渲染?
产品经理最初想要一个纯前端页面,用Axios调后端API。但我一想:这不就是个只读展示页吗?何必搞前后端分离增加复杂度?于是决定用Django自带的模板系统直接渲染HTML。
视图函数长这样:
# views.py
from django.shortcuts import render
from .models import Block
def block_list(request):
blocks = Block.objects.all()[:100] # 只取最新100个
return render(request, 'blocks/list.html', {'blocks': blocks})
模板文件list.html也很简单:
<!-- templates/blocks/list.html -->
<table>
<thead>
<tr><th>Height</th><th>Timestamp</th><th>Tx Count</th></tr>
</thead>
<tbody>
{% for block in blocks %}
<tr>
<td>{{ block.number }}</td>
<td>{{ block.timestamp|date:"Y-m-d H:i:s" }}</td>
<td>{{ block.transaction_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
是不是有种回到2010年的感觉?但说实话,对于内部工具或简单展示页,服务端渲染反而更快上线。而且Django的模板语言足够安全(自动转义XSS),比手写JS拼HTML靠谱多了。
性能优化:别让N+1查询搞垮你
当我把数据量从100条扩大到10000条做压力测试时,页面加载直接飙到5秒!打开Django Debug Toolbar一看——好家伙,每个区块都单独查了一次数据库(虽然这里没关联表,但原理类似)。
虽然这次没N+1问题,但让我意识到:Django ORM的懒加载机制在批量操作时很危险。解决方案其实很简单——用values()或only()明确指定字段,减少内存占用:
blocks = Block.objects.values('number', 'timestamp', 'transaction_count').order_by('-number')[:100]
如果真遇到外键关联,记得用select_related()或prefetch_related()。这点和Hibernate的fetch join思想很像,只是语法更简洁。
部署上线:从本地到生产环境的惊魂夜
最刺激的还是部署。我们公司用Kubernetes,但运维大哥说:“Django项目太小,先扔到一台ECS上跑吧。”于是我写了Dockerfile:
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "myblockchain_site.wsgi:application", "--bind", "0.0.0.0:8000"]
注意:千万别在生产环境用runserver! 它是单线程的,扛不住真实流量。我们用Gunicorn作为WSGI服务器,配合Nginx做反向代理。
结果上线当晚,监控报警:CPU 100%!查日志发现是某个爬虫疯狂请求/admin页面。Django Admin默认没加任何防护,我赶紧在Nginx层加了IP白名单:
location /admin {
allow 192.168.1.0/24;
deny all;
}
顺便在settings.py里关闭了DEBUG模式:
DEBUG = False
ALLOWED_HOSTS = ['your-domain.com']
这两个配置漏掉任何一个,都有可能造成信息泄露甚至RCE(远程代码执行)。血的教训啊!
和Springboot对比:Python后端的“快”与“慢”
作为一个长期写Springboot的人,我对Django的感受很矛盾:
| 维度 | Django | Springboot |
|---|---|---|
| 启动速度 | ⚡️ 极快(秒级) | 🐢 较慢(JVM冷启动) |
| 开发效率 | ✅ 高(内置功能多) | 🔧 中(需集成各种starter) |
| 类型安全 | ❌ 弱(动态语言) | ✅ 强(编译时检查) |
| 生态成熟度 | 📦 丰富(尤其Web领域) | 🌐 全面(企业级支持强) |
| 调试体验 | 👀 依赖print/logging | 🐞 IDE断点调试丝滑 |
说实话,Django适合快速验证想法,Springboot适合构建长期维护的系统。而区块链这种新兴领域,往往需要快速迭代原型——所以选Django,没毛病。
最后:跳槽到底值不值?
写完这个小项目,我其实有点释然了。虽然技术栈变了,但底层逻辑没变:数据库设计、接口规范、性能意识、安全防护……这些才是程序员的核心能力。Django也好,Springboot也罢,甚至未来要学的Rust或Go,都是工具而已。
至于跳槽?我现在觉得,迷茫期不可怕,可怕的是停止学习。至少现在,我能理直气壮地在简历上写:“熟悉Django Web开发,有区块链数据展示项目经验”。
哦对了,产品经理今天又来找我:“下个需求是做个NFT市场……用Django能做吗?”
我深吸一口气,戴上耳机,打开了VS Code。
“生活不止眼前的苟且,还有下个需求的deadline。” —— 某不愿透露姓名的Python萌新

评论 0