Django初体验:从零搭建一个能跑的Python网站

模型接口玩家
2025-12-29 10:13
阅读 223

上周五凌晨两点,我正窝在工位上和一个诡异的Redis缓存穿透问题死磕,突然想起自己还在刷LeetCode准备跳槽。这时候产品经理又发来消息:“能不能先搞个简单的管理后台出来?下周就要演示了。”我盯着屏幕上满屏的Go微服务日志,叹了口气——得,又是熟悉的“既要、又要、还要”。

作为一个常年用Vim写代码、连IDE都懒得装的老后端,我对前端向来是敬而远之。但这次躲不掉了:领导说“综合能力要提升”,暗示跳槽前得有点全栈经验。行吧,那就拿Django练手,毕竟Python生态里它最省事。


为什么选Django而不是Flask?

其实我一开始想用Flask,轻量、灵活,符合我们服务端开发的审美。但转念一想:我现在每天被线上事故追着跑,哪有精力从零搭轮子?Django自带Admin、ORM、用户认证、CSRF防护……一套全家桶,正好适合我这种只想快速交付的打工人。

而且说实话,我们团队最近在评估技术栈收敛。虽然主力是Go写的微服务,但内部工具链用Python更高效。Django这种“约定优于配置”的框架,反而能减少团队沟通成本——毕竟没人想半夜三点还在争论路由怎么写。


创建项目:比想象中快得多

打开终端(没错,我还在用iTerm2 + Vim),几行命令搞定:

pip install django
django-admin startproject mysite
cd mysite
python manage.py runserver

浏览器打开 http://127.0 .0.1:8000,经典的火箭图标出现。那一刻我居然有点感动——多久没见到这么顺利的Hello World了?上个月用某个国产框架,光配环境就折腾了两天。

不过别高兴太早。生产环境可不能直接用runserver。我立马在settings.py里加了几个关键配置:

# 生产环境必须关掉
DEBUG = False

# 允许的域名
ALLOWED_HOSTS = ['your-domain.com']

# 数据库换成PostgreSQL(别再用SQLite上生产了!)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'USER': 'myuser',
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': 'db.internal',
        'PORT': '5432',
    }
}

这里有个血泪教训:去年双11前,测试环境用SQLite跑得好好的,上线后并发一高直接锁表。运维老哥半夜打电话骂我:“你当PostgreSQL是玩具吗?” 从那以后,本地开发我也强制用Docker起PostgreSQL。


写个博客应用:从前端到后端串起来

为了演示“综合”能力,我决定做个极简博客系统。需求很简单:

  • 用户能发布文章
  • 文章列表页展示标题和摘要
  • 点进去看全文

模型设计:别小看这个环节

很多新手直接开写视图,但我作为服务端老油条,第一反应是数据库设计。在models.py里定义:

from django.db import models
from django.contrib.auth.models import User

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        indexes = [
            models.Index(fields=['created_at']),
            models.Index(fields=['author', '-created_at']),
        ]

注意两点:

  1. 外键关联User:直接复用Django内置的用户系统,省得自己搞注册登录
  2. 手动加索引:别依赖Django自动建的索引,查询性能会崩。我们线上就吃过亏——一个没加联合索引的订单表,高峰期QPS直接打满CPU

生成迁移文件并执行:

python manage.py makemigrations
python manage.py migrate

顺手创建个超级用户:

python manage.py createsuperuser

然后访问 /admin,用刚才的账号登录——Wow!一个功能完整的后台管理界面自动生成了。产品经理要是看到这个,估计能笑醒。


视图与模板:前端部分怎么搞?

我知道很多后端讨厌写HTML,但Django的模板系统其实挺克制。我在views.py里写了个简单视图:

from django.shortcuts import render
from .models import Article

def article_list(request):
    articles = Article.objects.select_related('author').order_by('-created_at')[:10]
    return render(request, 'blog/list.html', {'articles': articles})

关键点:select_related 避免N+1查询。这可是性能优化的基本功——上次review代码时,实习生没加这个,测试环境查100篇文章触发了101次SQL,被我当场抓包。

模板文件list.html放在templates/blog/目录下:

<!DOCTYPE html>
<html>
<head>
    <title>我的博客</title>
    <!-- 别笑,这就是我的前端水平 -->
    <style>
        .article { margin-bottom: 20px; padding: 10px; border-left: 3px solid #eee; }
    </style>
</head>
<body>
    <h1>最新文章</h1>
    {% for article in articles %}
    <div class="article">
        <h2>{{ article.title }}</h2>
        <p>作者: {{ article.author.username }} | {{ article.created_at|date:"Y-m-d H:i" }}</p>
        <p>{{ article.content|truncatewords:30 }}</p>
    </div>
    {% empty %}
    <p>暂无文章</p>
    {% endfor %}
</body>
</html>

虽然丑,但能跑。前端同事看了可能会摇头,但对内部工具来说够用了。真要上用户产品,我肯定甩给专业前端——毕竟我们的KPI不是拼UI。


性能考量:别让Django变“单机版”

很多人说Django慢,其实是用错了姿势。分享几个生产经验:

1. 静态文件交给Nginx

Django处理静态文件效率低,必须在部署时用Nginx代理:

location /static/ {
    alias /path/to/staticfiles/;
    expires 30d;
}

2. 数据库连接池

默认的DB连接每次请求新建,高并发下会耗尽连接数。我们用django-db-geventpool(配合Gunicorn)解决。

3. 缓存策略

对于文章详情页,加上简单的cache:

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)  # 缓存15分钟
def article_detail(request, pk):
    # ...

性能对比(本地压测)

配置 QPS (wrk -t4 -c100 -d30s)
默认Django 220
+ Gunicorn (4 workers) 850
+ Nginx静态文件分离 920
+ Redis缓存热点数据 1450

可见,合理配置下Django完全能扛住内部系统流量。当然,如果是高并发C端产品,我们还是会用Go重写核心服务——但Django做MVP或管理后台,效率无敌。


部署上线:踩坑实录

最后一步最致命。我用Docker打包,结果遇到经典问题:时区不对

Django默认UTC时间,但用户看到的是本地时间。解决方案:

# settings.py
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True  # 必须设为True才能正确转换

另一个坑:SECRET_KEY泄露。千万别把密钥写死在代码里!我们用环境变量:

SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')

CI/CD脚本里注入密钥,Git仓库干干净净。这都是被安全审计逼出来的习惯——去年因为密钥提交到GitHub,被罚写了三千字检讨。


Django vs Go:我的真实想法

写完这个小项目,我反而更理解团队的技术选型了。Django适合:

  • 快速验证业务想法
  • 内部管理后台
  • 原型开发

Go适合:

  • 高并发API服务
  • 微服务核心逻辑
  • 对启动时间和内存敏感的场景

两者根本不是对手,而是互补。我们现在的架构就是:Django做运营后台 + Go微服务集群 + Vue前端。各司其职,谁也别鄙视谁。


结语:打工人的时间管理术

凌晨三点,终于把Django项目跑通了。看了看LeetCode还没刷,又瞄了眼招聘软件上那些“精通Django”的JD,苦笑一下。

其实学Django不是为了转全栈,而是让自己在跳槽时多一张底牌。后端工程师的核心能力永远是系统设计性能优化,框架只是工具。但在这个卷成麻花的时代,多会一个技能,简历就能多过一轮筛选。

所以啊,别纠结“该不该学前端”。当你能用Django半小时搭出一个可用系统,用Go写出高性能服务,用Vim流畅编码——你早就超越了90%的“纯后端”。

(完)

P.S. 刚才测试同学发消息说新需求来了……算了,先去改bug,Django教程就写到这儿吧。反正也没人看我博客,都是给自己留的笔记 😅

评论 0

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