Django入门教程:搭建你的第一个Python网站(别慌,不是教你怎么发币)

林洋
2025-12-16 06:53
阅读 238

大家好,我是字节跳动基础架构组的一名后端老搬砖人,入司快五年了。每天和 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 = FalseALLOWED_HOSTS 配好,不然线上等着被扫吧 😅

Happy coding!

评论 0

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