我用 Django 搞了个“区块链风”网站?入职两个月的血泪初体验
大家好,我是小林,一个刚入职某中型 SaaS 公司不到俩月的后端“萌新”。名义上是正式员工,实际上还在试用期战战兢兢地活着——每天早上打开电脑第一件事就是看 GitLab 有没有被 Code Review 吐槽,下午三点准时祈祷产品经理别突然甩个需求过来。
说来惭愧,我虽然在校期间折腾过 Rust、玩过 Solidity 写智能合约(对,就是那个和区块链沾边的玩意),但进公司第一天就被老架构师一句话打回现实:“小林啊,新技术我们鼓励学,但线上系统必须稳如老狗。你先用 Django 把用户管理模块搭起来。”
于是,就有了这篇教程。不,准确地说,是一篇“血泪踩坑实录”。本文全程基于我上周五加班到九点、靠 ChatGPT 和 Claude 轮流续命才跑通的真实项目。如果你也刚入行,或者正被领导逼着用 Django 快速出活,那咱们算是一条船上的人了。
为啥是我这个“区块链民工”来写 Django 教程?
先交代背景:我本科毕业设计搞的是基于以太坊的去中心化投票系统,满脑子都是 Merkle Tree 和 Gas Fee。结果入职后发现,公司主力技术栈是 Python + Django + PostgreSQL,连 Redis 都只用来做缓存,别说区块链了——我们连 Web3 的影子都没见过。
但上周二,产品突然丢来一个需求:“我们要做一个内部工具平台,支持多租户、权限隔离,还要能快速接入新模块。” Deadline 是下周五上线 MVP。我当场瞳孔地震:这不就是典型的 CRUD 系统吗?但老板补了一句:“界面要像 Notion,性能要扛住 500 并发,下周演示给投资人看。”
行吧。既然不能上链(其实根本没必要),那就老老实实用 Django 搞个“看起来很高级”的网站吧。而且说实话,Django 的 admin 后台和 ORM 真香,比手写 SQL 省了八百条命。
从零开始:三行命令跑起你的第一个 Django 站点
别被吓到,Django 虽然“全功能”,但起步其实超快。前提是——你别像我一样手贱升级 Python 到 3.12 结果一堆包报错。
# 创建虚拟环境(强烈建议!)
python -m venv mysite_env
source mysite_env/bin/activate # Linux/Mac
# mysite_env\Scripts\activate # Windows
# 安装 Django(我用的是 4.2 LTS 版,稳定!)
pip install django==4.2.7
# 创建项目
django-admin startproject mysite
cd mysite
python manage.py runserver
浏览器打开 http://127.0.0.1:8000,看到那个火箭图标了吗?恭喜,你的“区块链级”网站已经上线了(手动狗头)。
🤓 小贴士:千万别在公司内网直接
runserver对外暴露!我们运维大哥上周刚骂完一个实习生,说他把开发服务器绑到 0.0.0.0 还开了公网 IP,差点被扫爆。
数据库设计:别让字段命名毁掉你的职业生涯
我们这次要做的是一个简单的“项目看板”系统,类似 Trello,但砍掉了 90% 功能。核心模型就两个:Project 和 Task。
# models.py
from django.db import models
from django.contrib.auth.models import User
class Project(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Task(models.Model):
STATUS_CHOICES = [
('todo', '待处理'),
('doing', '进行中'),
('done', '已完成'),
]
title = models.CharField(max_length=200)
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='tasks')
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='todo')
assignee = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
due_date = models.DateField(null=True, blank=True)
这里有几个血泪教训:
- 别用中文字段名:虽然 Django 支持
verbose_name显示中文,但数据库列名还是英文。否则以后写 raw SQL 你会疯。 - 外键别乱删:
on_delete=models.CASCADE要慎用!我们测试环境曾因为删一个用户,连带干掉了 200 个项目,测试妹子差点拿键盘砸我。 - 时间字段加索引:如果经常按
created_at查询,记得加db_index=True。不然等数据量上来,慢查询日志里全是你的名字。
视图与模板:Django 的 MTV 架构真不是吹的
Django 用的是 MTV(Model-Template-View),不是 MVC。别杠,官方就这么叫。
我一开始想直接用 FBV(Function-Based View),但老工程师看了直摇头:“现在谁还手写分页逻辑?用 CBV(Class-Based View)+ ListView,三行搞定。”
于是有了下面这段:
# views.py
from django.views.generic import ListView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Project
class ProjectListView(LoginRequiredMixin, ListView):
model = Project
template_name = 'projects/list.html'
context_object_name = 'projects'
def get_queryset(self):
return Project.objects.filter(owner=self.request.user)
配合模板:
<!-- templates/projects/list.html -->
{% extends "base.html" %}
{% block content %}
<h1>我的项目</h1>
<ul>
{% for project in projects %}
<li>{{ project.name }} - {{ project.created_at|date:"Y-m-d" }}</li>
{% endfor %}
</ul>
{% endblock %}
是不是清爽多了?而且自带登录校验(LoginRequiredMixin),省得我手写 if not request.user.is_authenticated。
💡 吐槽:我们前端同事看到模板里的
{% %}直呼“这是什么远古语法”,我说这是 Django 的传承,他回我“传承个锤子,不如 JSX”。算了,各自安好。
区块链?不,但我们可以“假装有链”
说到关键词“区块链”——我知道你们等着呢。实话实说,这个项目跟区块链半毛钱关系没有。但为了满足标题要求(以及我那点虚荣心),我在后台悄悄加了个“操作日志”功能,记录每次任务状态变更,并生成一个 SHA256 哈希值,美其名曰“不可篡改日志”。
import hashlib
from django.db import models
class TaskLog(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
old_status = models.CharField(max_length=10)
new_status = models.CharField(max_length=10)
changed_by = models.ForeignKey(User, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
hash = models.CharField(max_length=64, unique=True)
def save(self, *args, **kwargs):
if not self.hash:
data = f"{self.task.id}{self.old_status}{self.new_status}{self.changed_by.id}{self.timestamp}"
self.hash = hashlib.sha256(data.encode()).hexdigest()
super().save(*args, **kwargs)
这样每次状态变更都会生成唯一哈希,理论上可以链式追溯(虽然没真做链)。产品经理看了直夸“有 Web3 内味了”,我默默咽下一口老血。
性能与部署:别让 demo 变成事故
本地跑得欢,上线火葬场。这是我们团队的座右铭。
为防翻车,我做了几件事:
- 启用 Gunicorn + Nginx:别再用
runserver上生产! - 静态文件交给 CDN:Django 自带的 staticfiles 在高并发下会卡死。
- 数据库连接池:用
django-db-geventpool或直接上 PgBouncer。 - 缓存关键查询:比如用户权限列表,用 Redis 缓存 5 分钟。
部署配置对比表:
| 组件 | 开发环境 | 生产环境 |
|---|---|---|
| Web Server | Django dev server | Gunicorn + Nginx |
| DB | SQLite | PostgreSQL 14 |
| Static Files | 本地 serve | AWS S3 + CloudFront |
| 日志 | 控制台输出 | ELK 集中收集 |
| 缓存 | 无 | Redis |
上线前夜,我和运维兄弟一起压测。用 Locust 模拟 500 用户并发访问项目列表页,QPS 从 12 暴涨到 180+,全靠加了 select_related('owner') 和 Redis 缓存。那一刻,我终于理解什么叫“性能是抠出来的”。
写在最后:新人如何快速融入技术栈?
入职两个月,我最大的感悟是:别炫技,先交付。
我曾经以为会写智能合约就很牛,结果发现公司最需要的是能把用户注册登录流程写得又快又稳的人。Django 的“开箱即用”特性在这种场景下简直是神兵利器——Admin 后台五分钟搭好,用户认证系统不用自己造轮子,ORM 让我告别了 SQL 注入噩梦。
当然,我也在业余时间继续研究区块链。但工作归工作,爱好归爱好。就像我们 CTO 说的:“先学会用螺丝刀,再想着造火箭。”
所以,如果你也是刚入行的小白,别怕从 Django 这种“老派”框架开始。它可能不够酷,但它能让你在试用期活下去——而活下去,才有机会去折腾那些真正酷的东西。
对了,今天 HR 刚通知我,试用期考核通过了。据说是因为“项目交付及时、代码规范、没惹运维生气”。行吧,这大概就是职场生存的终极奥义了。
附:常用命令速查
# 创建 app
python manage.py startapp projects
# 生成迁移文件
python manage.py makemigrations
# 执行迁移
python manage.py migrate
# 创建超级用户(用于 admin)
python manage.py createsuperuser
# 收集静态文件(部署用)
python manage.py collectstatic --noinput
祝各位都能顺利转正,少背锅,多涨薪。代码无 bug,生活有惊喜。

评论 0