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

一人公司实验室
2026-01-14 17:29
阅读 610

上周五晚上十一点,我还在工位上盯着 Vim 里的一堆 Go 代码发呆。突然想起自己在滴滴已经待了快四年,从司机端调度系统的小透明,一路熬成现在能拍板接口设计的“老油条”。最近刷招聘软件刷得有点上头,发现不少心仪岗位都写着“熟悉 Python/Django 优先”——而我呢?除了写过几个 Flask 脚本,Django 还真没碰过。

这不就尴尬了。面试题挑战里动不动就问“Django 的 MVT 模型和中间件机制”,我支支吾吾答不上来,心里直打鼓。为了不被下一轮面试官当面问懵,我决定:周末两天,必须用 Django 搭出一个能跑的网站,哪怕只是个 Hello World,也得搞明白底层逻辑。

于是,就有了这篇实战记录。别指望什么高深理论,就是一个后端老狗在安全红线内,用最稳妥的方式,从零开始踩坑、填坑、再踩坑的过程。


为什么选 Django?安全不是口号,是底线

在滴滴做司机端业务,我们对“安全”两个字刻进骨子里。不是说防黑客那种炫酷攻防,而是数据一致性、权限控制、输入校验、SQL 注入防护这些枯燥但致命的细节。比如去年双11前,有个实习生写了段裸拼 SQL 的接口,测试环境跑得好好的,上线后被恶意参数直接拖垮了 MySQL 主库——那天运维兄弟差点把键盘砸了。

所以当我翻看 Django 文档时,第一眼就被它的“默认安全”设计打动了:

  • 自动转义模板变量:防止 XSS
  • CSRF 保护中间件默认开启
  • ORM 层天然防 SQL 注入
  • 用户认证系统开箱即用

这些不是“可选项”,而是框架强制你走的安全路径。对一个常年在 deadline 压力下写代码的人来说,这种“不让你犯错”的设计,简直是救命稻草。


环境搭建:别在第一步就翻车

首先,别用系统自带的 Python!我见过太多人因为 macOS 自带的 Python 2.7 把环境搞崩。老规矩,用 pyenv + virtualenv 隔离:

# 安装 pyenv(Mac 用户)
brew install pyenv

# 安装 Python 3.10
pyenv install 3.10.12
pyenv global 3.10.12

# 创建虚拟环境
python -m venv django_demo
source django_demo/bin/activate

# 安装 Django
pip install django

检查一下:

django-admin --version
# 输出 4.2.x 或更高

血泪教训:千万别在全局 pip install!上次隔壁组新人直接 sudo pip install,结果把生产服务器的依赖搞乱了,回滚花了三小时。


项目初始化:那个经典的 startproject

进入工作目录,执行:

django-admin startproject mysite
cd mysite

这时候你会看到这样的结构:

mysite/
├── manage.py
└── mysite/
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

注意:外层 mysite 是项目容器,内层 mysite 才是真正的 Python 包。很多新手会混淆,导致 import 错误。

启动开发服务器:

python manage.py runserver

浏览器访问 http://127.0.0.1:8000,看到那匹火箭小马(Django 默认欢迎页),恭喜你,万里长征第一步完成。


加个功能:司机信息展示页(贴近我的老本行)

光有 Hello World 不够,得结合点实际业务。我就模拟一个“司机信息查询”页面吧——毕竟在滴滴三年多,天天跟司机状态、接单量、服务分打交道。

第一步:创建 App

Django 里功能模块叫 App,不是“应用”那种大词,而是可复用的组件单元。

python manage.py startapp drivers

然后在 mysite/settings.pyINSTALLED_APPS 里注册:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'drivers',  # <-- 加这一行
]

第二步:定义模型(Model)

drivers/models.py 里写:

from django.db import models

class Driver(models.Model):
    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=20, unique=True)
    license_plate = models.CharField(max_length=20)
    service_score = models.FloatField(default=5.0)  # 服务分,0-5
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.name} ({self.license_plate})"

注意几点:

  • phone 加了 unique=True,避免重复注册
  • service_scoreFloatField,虽然精度问题存在,但业务场景够用
  • auto_now_add 自动记录创建时间,省去手动赋值

第三步:生成并执行迁移

Django 用迁移(migration)管理数据库变更,类似 Rails 的 ActiveRecord。

python manage.py makemigrations
python manage.py migrate

第一条命令生成 drivers/migrations/0001_initial.py,第二条把表真正建到 SQLite(默认数据库)里。

安全提醒:生产环境别用 SQLite!但本地开发完全 OK,别一上来就折腾 PostgreSQL,容易劝退。


写个视图:把数据吐出来

drivers/views.py

from django.shortcuts import render
from .models import Driver

def driver_list(request):
    # 安全第一:只查活跃司机
    active_drivers = Driver.objects.filter(is_active=True)
    return render(request, 'drivers/list.html', {'drivers': active_drivers})

这里用了 filter(is_active=True),而不是直接 all()。为什么?因为在真实业务中,永远不要默认暴露所有数据。曾经有同事忘了加状态过滤,把已封禁司机的信息也返回了,差点被合规部门约谈。

配置 URL

drivers/urls.py(新建):

from django.urls import path
from . import views

urlpatterns = [
    path('', views.driver_list, name='driver_list'),
]

然后在主 mysite/urls.py 中 include:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('drivers/', include('drivers.urls')),
]

现在访问 /drivers/ 就能触发视图。


模板渲染:简单但别偷懒

Django 模板语言很基础,但足够安全。在 drivers/templates/drivers/list.html

<!DOCTYPE html>
<html>
<head>
    <title>活跃司机列表</title>
</head>
<body>
    <h1>当前活跃司机</h1>
    {% if drivers %}
        <ul>
        {% for driver in drivers %}
            <li>
                {{ driver.name }} - 
                车牌: {{ driver.license_plate }} - 
                服务分: {{ driver.service_score|floatformat:2 }}
            </li>
        {% endfor %}
        </ul>
    {% else %}
        <p>暂无活跃司机</p>
    {% endif %}
</body>
</html>

注意 {{ driver.service_score|floatformat:2 }},用过滤器控制小数位。别在模板里写复杂逻辑!这是 Django 的哲学:模板只负责展示,逻辑留在视图或模型。


加点真实感:用管理后台快速造数据

Django 自带 admin,简直是开发神器。先注册模型:

# drivers/admin.py
from django.contrib import admin
from .models import Driver

@admin.register(Driver)
class DriverAdmin(admin.ModelAdmin):
    list_display = ('name', 'phone', 'license_plate', 'service_score', 'is_active')
    list_filter = ('is_active', 'service_score')
    search_fields = ('name', 'phone')

然后创建超级用户:

python manage.py createsuperuser
# 按提示输入用户名、邮箱、密码

启动服务,访问 /admin,登录后就能增删改查司机数据了。我在里面加了三条测试数据,刷新 /drivers/,页面立刻有了内容。

吐槽:产品经理总说“这个功能很简单,加个字段就行”,但每次加字段都要改 model、migration、admin、serializer、前端……累死。不过 Django 的 admin 至少让我省了 80% 的 CRUD 工作。


安全加固:别以为开发服务器就安全

虽然 runserver 只用于开发,但有些习惯要养成:

  1. 关闭 DEBUG 模式
    settings.py 中,确保 DEBUG = False 在生产环境生效。否则错误页面会暴露代码路径、环境变量等敏感信息。

  2. 设置 ALLOWED_HOSTS
    生产环境必须明确指定允许的域名,否则会 400 Bad Request。

  3. 密码别硬编码
    敏感配置用环境变量:

    # settings.py
    import os
    SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'fallback-for-dev')
    
  4. 静态文件处理
    开发时 Django 自动 serve static,但生产必须用 Nginx 或 CDN。别图省事!


面试题挑战:我被问到的几个 Django 问题

为了这次跳槽准备,我整理了几个高频面试题,顺便验证自己的理解:

面试题 我的回答要点
Django 的 MVT 和 MVC 有什么区别? MVT 中 View 是业务逻辑(相当于 Controller),Template 是视图(View),Model 不变。Django 把 URL 路由作为显式组件,更清晰。
中间件怎么工作的? 类似洋葱模型,请求进来层层处理(如认证、日志),响应出去再层层返回。自定义中间件可做 IP 限流、请求耗时统计。
ORM 查询如何优化? 1. 用 select_related 减少外键查询 2. prefetch_related 处理多对多 3. 避免在循环里查数据库 4. 必要时用 only() 限制字段
如何防止 CSRF? Django 默认启用 CsrfViewMiddleware,模板中用 {% csrf_token %},AJAX 请求需从 cookie 读取 token 并放入 header。

这些问题,光背答案没用,必须动手试过才知道坑在哪。比如我一开始在 AJAX 请求里忘加 CSRF token,调试半天才发现是 403 Forbidden。


总结:两天入门,值不值?

从周五晚上到周日晚上,我用 Django 搞定了一个带数据模型、视图、模板、管理后台的完整小站。虽然功能简单,但整个流程走通了,心里踏实多了。

更重要的是,我理解了为什么那么多公司用 Django 做内部系统、MVP 产品——它把安全、规范、可维护性这些“苦活”都封装好了,让你专注业务逻辑。不像某些框架,自由度高到让你随时掉进坑里。

当然,Django 也有缺点:同步阻塞模型不适合高并发 IO 场景(比如司机实时位置推送),这时候就得上 ASGI + Channels。但对大多数 CRUD 应用,它依然是稳如老狗的选择。

最后说句掏心窝的话:技术栈只是工具,解决问题的能力才是核心。我在滴滴写 Go,不代表我不能学 Python;你用 Vue,也不妨碍你理解 React 的思路。保持学习,保持好奇,别被“我是某某语言程序员”这种标签困住。

对了,如果这篇文章帮你避开了某个坑,或者你在面试中遇到 Django 题顺利过关——记得回来点个赞。毕竟,程序员的世界,互相照亮才走得远。

(完)

评论 0

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