Django入门教程:搭建你的第一个Python网站(别慌,不是教你怎么发币)
大家好,我是字节跳动基础架构组的一名后端老搬砖人,入司快五年了。每天和 Go、K8s、分布式锁打交道,VSCode 里插件多到启动都要两秒。上周五晚上,我正对着一个慢如蜗牛的链上交易验证服务抓狂——是的,我们最近在搞一个内部区块链数据索引平台(别问,问就是“技术探索”),结果 PM 突然跑来说:“能不能先搭个前端页面展示下数据?就简单点,能看就行。”
我说:“前端?我们不是有 FaaS + React 的标准链路吗?”
他眨眨眼:“来不及了,下周三就要给老板 demo,而且……你不是会 Python 吗?听说 Django 一天就能搭个网站?”
行吧。被 deadline 逼着,我又翻出了尘封已久的 Python 技能包。于是,就有了这篇《Django 入门教程》。别误会,这不是要教你发币(虽然提到了区块链),而是手把手带你用 Django 搭一个能跑、能查、能扩展的最小可用网站——顺便分享我在字节这些年对资源利用率、代码可维护性和快速交付的一些执念。
为啥选 Django?Go 不香吗?
在字节,Go 是绝对的主流语言,性能高、并发强、部署轻,连我们内部的配置中心都用 Go 重写了。但这次情况特殊:
- 时间紧:三天内出 demo
- 功能简单:就是 CRUD + 展示
- 团队没人会 React(别笑,真事)
Django 的“开箱即用”特性就派上用场了。自带 ORM、Admin、用户认证、开发服务器,一行命令 python manage.py runserver 就能跑起来。对我们这种常年写微服务的人来说,简直像回到了大学时代——那种“写完就能看到网页”的原始快乐。
当然,上线肯定不能这么干。但在 POC(Proof of Concept)阶段,快速验证想法比架构完美更重要。这也是我们组 leader 经常说的:“先跑通,再优化”。
动手!从零开始
1. 环境准备
我本地用的是 pyenv + pipenv,公司推荐的虚拟环境管理方式(毕竟谁也不想 global 装一堆依赖然后炸掉系统)。假设你已经装好了 Python 3.9+:
pip install django
django-admin startproject blockchain_explorer
cd blockchain_explorer
python manage.py startapp blocks
这里我把 app 命名为 blocks,因为我们要展示区块链的区块数据。别想太多,暂时就是个数据库表。
📌 小贴士:在字节,所有新项目都要过 SAST 扫描 和 依赖白名单。所以实际工作中,我们会用内部镜像源拉 Django,而不是直接 pip install。但为了教程通用性,这里省略了。
2. 数据模型设计
既然是区块链 explorer,最核心的数据就是区块(Block)。我们先建个简单的模型:
# blocks/models.py
from django.db import models
class Block(models.Model):
block_number = models.BigIntegerField(unique=True, help_text="区块高度")
hash = models.CharField(max_length=66, unique=True, help_text="区块哈希 (0x...)")
timestamp = models.DateTimeField(help_text="出块时间")
transaction_count = models.IntegerField(default=0, help_text="交易数量")
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "blockchain_blocks"
indexes = [
models.Index(fields=["block_number"]),
models.Index(fields=["timestamp"]),
]
def __str__(self):
return f"Block #{self.block_number}"
注意几个细节:
- 用了
BigIntegerField,因为以太坊区块号已经超过 2000 万了 - 加了数据库索引,不然按时间查会慢死(别问我怎么知道的)
- 表名显式指定,避免 Django 自动生成的
app_model格式,方便 DBA 管理
3. 配置数据库 & 迁移
本地开发我直接用 SQLite,但生产环境必须上 MySQL 或 PostgreSQL。在 settings.py 里改一下:
# blockchain_explorer/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
然后生成并执行迁移:
python manage.py makemigrations
python manage.py migrate
搞定!现在数据库里已经有 blockchain_blocks 表了。
写个 API 接口
虽然 Django 有模板渲染能力,但作为后端工程师,我更习惯写 JSON API。用 Django REST framework(DRF)是最稳的选择:
pip install djangorestframework
注册 app 并配置:
# settings.py
INSTALLED_APPS = [
...
'rest_framework',
'blocks',
]
写个简单的 ViewSet:
# blocks/views.py
from rest_framework import viewsets
from .models import Block
from .serializers import BlockSerializer
class BlockViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Block.objects.all().order_by('-block_number')
serializer_class = BlockSerializer
pagination_class = None # demo 阶段先关分页
Serializer 也很简单:
# blocks/serializers.py
from rest_framework import serializers
from .models import Block
class BlockSerializer(serializers.ModelSerializer):
class Meta:
model = Block
fields = ['block_number', 'hash', 'timestamp', 'transaction_count']
最后配路由:
# blockchain_explorer/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from blocks.views import BlockViewSet
router = DefaultRouter()
router.register(r'blocks', BlockViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
现在访问 http://127.0.0.1:8000/api/blocks/,就能看到空列表了。
导入真实数据(模拟)
为了 demo 效果,我写了个脚本往数据库塞点假数据:
# scripts/fake_data.py
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blockchain_explorer.settings")
import django
django.setup()
from blocks.models import Block
from datetime import datetime, timedelta
for i in range(1000, 0, -1):
Block.objects.get_or_create(
block_number=i,
defaults={
'hash': f'0x{"a"*64}',
'timestamp': datetime.now() - timedelta(minutes=i),
'transaction_count': i * 2,
}
)
运行它:
python scripts/fake_data.py
刷新 API,数据出来了!🎉
性能与资源考量(重点!)
到这里,一个能跑的网站就算搭好了。但在字节,光“能跑”远远不够。我们得考虑:
| 问题 | 解决方案 |
|---|---|
| 数据量大时查询慢 | 加缓存(Redis)、分页、读写分离 |
| 单机扛不住流量 | 上 K8s + HPA 自动扩缩容 |
| 日志没规范 | 接入公司统一日志平台(Lark Log) |
| 没监控 | 打点埋入 Prometheus |
比如,这个 BlockViewSet 如果直接暴露给公网,高峰期可能把数据库打挂。所以我们通常会在前面加一层缓存:
# views.py (简化版)
from django.core.cache import cache
class BlockViewSet(viewsets.ReadOnlyModelViewSet):
def get_queryset(self):
cache_key = "latest_blocks"
qs = cache.get(cache_key)
if qs is None:
qs = Block.objects.all().order_by('-block_number')[:100]
cache.set(cache_key, qs, 60) # 缓存60秒
return qs
另外,不要在线上用 runserver!这是 Django 官方反复强调的。我们生产环境会用 Gunicorn + Nginx,或者直接打包成容器跑在 K8s 上。
最后:为什么这事值得做?
说实话,用 Django 写这种小工具,在我们组有点“不务正业”。但正是这些快速交付的能力,让我们能在大促前快速验证链路、在故障时快速搭个 debug 页面、甚至帮产品同学做个临时后台。
技术没有高低贵贱,合适场景用合适工具才是工程师的素养。Go 适合高并发微服务,Python 适合快速原型,区块链适合不可篡改场景——关键是你得清楚每种技术的边界和代价。
上周三 demo 很成功,老板说“这个 explorer 很清晰”。PM 高兴地请我喝了杯瑞幸(上海租房贵,省下的打车费刚好买咖啡)。而我,默默把这段 Django 代码提交到了内部 GitLab,并加了一行注释:
⚠️ Temporary solution. Will be replaced by Go service + GraphQL after Q3.
毕竟,在字节,临时方案永远只是临时的。
如果你也想试试 Django,不妨从今天开始:pip install django,然后 startproject。不用怕,没人会因为你用了 Python 而觉得你不专业——只要你的代码有测试、有文档、有监控,就是好代码。
对了,别忘了把 DEBUG = False 和 ALLOWED_HOSTS 配好,不然线上等着被扫吧 😅
Happy coding!

评论 0