Django初体验:从零搭个能跑的Python网站
上周五晚上十一点,我还在工位上盯着 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.py 的 INSTALLED_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_score用FloatField,虽然精度问题存在,但业务场景够用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 只用于开发,但有些习惯要养成:
关闭 DEBUG 模式
在settings.py中,确保DEBUG = False在生产环境生效。否则错误页面会暴露代码路径、环境变量等敏感信息。设置 ALLOWED_HOSTS
生产环境必须明确指定允许的域名,否则会 400 Bad Request。密码别硬编码
敏感配置用环境变量:# settings.py import os SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'fallback-for-dev')静态文件处理
开发时 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