Django入门教程:搭建你的第一个Python网站(一个刚跳槽程序员的踩坑实录)

生产环境勿扰
2025-12-17 04:16
阅读 670

上周五晚上十点半,我瘫在工位上盯着屏幕上不断报错的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 pythonwhich 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

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝