用Django搭个网站,比改需求还简单?
上周五晚上十点半,我瘫在工位上盯着屏幕上产品经理刚甩过来的PRD——“做一个基于区块链的用户积分系统原型,下周三演示”。当时我差点把手里那杯瑞幸捏爆。我们是外包公司,不是创业孵化器啊!更离谱的是,这项目连UI稿都没给全,就一句“先跑起来看看效果”。
但没办法,甲方爸爸的需求就是圣旨。作为在魔都某不知名外包公司摸爬滚打四年的老油条,我深知:与其抱怨,不如动手。反正VSCode里Python插件早就装好了,Django环境也配过八百遍。索性趁着周末,从零搭个最简版网站出来,至少能把“能跑”这个底线守住。
顺便说一句,最近面试季,好几个兄弟问我“Django和Flask区别是啥”,甚至有HR直接甩来一道面试题:“如何用Django实现一个简单的REST API?” 所以今天这篇,既是实战记录,也算给后来人铺点路。
为啥选Django?因为快!
我知道有人会说:“现在都2024年了,还用Django?不上FastAPI或者Go吗?” 兄弟,醒醒!我们是外包,不是字节。客户要的是快速交付、能跑就行、别崩就行。Django自带Admin后台、ORM、用户认证、安全防护(CSRF、XSS等),开箱即用。你让我三天内搞定一个带登录、增删改查的后台,我选Django闭着眼都能写完。
而且Python语法简洁,团队里新人上手快。上次实习生小李,学了两天就能改views.py,虽然把数据库migration搞炸了一次,但总比让他啃Spring Boot强。
环境搭建:别被pip坑了
首先,确保你装了Python 3.8+(推荐3.10)。我用的是pyenv管理版本,但如果你图省事,直接官网下也行。
# 创建虚拟环境(强烈建议!)
python -m venv django_env
source django_env/bin/activate # Linux/Mac
# django_env\Scripts\activate # Windows
# 安装Django
pip install django
血泪教训:千万别全局装包!我去年双11前上线一个项目,就因为没用虚拟环境,pip upgrade把系统依赖搞乱了,服务器直接502,运维大哥差点提刀来找我。
验证安装:
django-admin --version
# 输出类似:4.2.7
创建你的第一个项目
Django的“项目”(project)和“应用”(app)是两个概念。项目是整体容器,应用是功能模块。比如一个电商网站,项目叫shop_project,里面可能有user_app、order_app、product_app等。
django-admin startproject mysite
cd mysite
python manage.py runserver
访问 http://127.0.0.1:8000,看到那个火箭图标了吗?恭喜,你已经打败了全国90%的还没开始的人。
加个App:从Hello World到真实业务
光看欢迎页没用,得干点正事。我们按客户要求,先做个“用户积分记录”页面。虽然他说要“区块链”,但咱先做传统数据库版,后面再忽悠他“底层已预留区块链接口”(手动狗头)。
python manage.py startapp points
然后在mysite/settings.py里注册这个app:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'points', # ← 加这一行
]
设计模型:别一上来就搞复杂
客户说“积分要可追溯、不可篡改”,听着像区块链特性。但我们先别被唬住——外包的第一原则:用最简单的方式满足表面需求。
所以模型就这么设计:
# points/models.py
from django.db import models
from django.contrib.auth.models import User
class PointRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
amount = models.IntegerField() # 正为增加,负为扣除
reason = models.CharField(max_length=200) # 比如“签到奖励”、“兑换商品”
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user.username}: {self.amount} ({self.reason})"
注意:这里用了Django内置的User模型,省去了自己写注册登录的麻烦。外包讲究效率,重复造轮子?不存在的。
生成并执行迁移:
python manage.py makemigrations
python manage.py migrate
写个视图:别怕CBV,FBV也香
Django支持函数视图(FBV)和类视图(CBV)。我一般小项目用FBV,清晰直白;大项目用CBV,复用性强。
先来个简单的列表页:
# points/views.py
from django.shortcuts import render
from .models import PointRecord
def point_list(request):
records = PointRecord.objects.all().order_by('-created_at')
return render(request, 'points/list.html', {'records': records})
配个URL:
# points/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.point_list, name='point_list'),
]
别忘了在主urls里include:
# mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('points/', include('points.urls')),
]
模板:别追求花里胡哨
外包前端?不存在的。我们用Django模板凑合一下就行。创建points/templates/points/list.html:
<!DOCTYPE html>
<html>
<head>
<title>积分记录</title>
</head>
<body>
<h1>所有积分变动</h1>
<ul>
{% for record in records %}
<li>{{ record.created_at|date:"Y-m-d H:i" }} -
{{ record.user.username }}: {{ record.amount }} ({{ record.reason }}})
</li>
{% empty %}
<li>暂无记录</li>
{% endfor %}
</ul>
</body>
</html>
启动服务,访问 /points/,看到数据了吗?如果没有,去/admin/加几条测试数据。
提示:先创建超级用户:
python manage.py createsuperuser,然后登录admin后台,你会发现PointRecord自动出现在管理界面——这就是Django Admin的魔法。
关于“区块链”的真相
回到开头那个需求。客户嘴里的“区块链”,大概率只是想要“数据不可篡改 + 可追溯”。其实在传统数据库里,只要做到以下几点,也能满足:
- 禁止物理删除:用
is_deleted字段软删除 - 记录操作日志:每次变更都留痕
- 关键字段只增不减:比如积分余额,只通过原子操作更新
真要上链?成本太高,运维复杂,还不一定有用。我跟客户说:“我们用Django的审计日志 + 时间戳 + 数字签名,效果一样,还能快速上线。” 他居然信了。
面试时如果被问“如何结合区块链”,你可以答:“Django负责业务逻辑和API,区块链作为底层存储或验证层,通过智能合约交互。但需评估性能和成本。” —— 这话术,稳!
性能与架构:别等上线才优化
虽然这是demo,但我习惯一开始就考虑生产环境。几个建议:
1. 数据库查询优化
上面的point_list视图有个N+1问题:每条记录都要查一次user。应该用select_related:
records = PointRecord.objects.select_related('user').order_by('-created_at')
2. 分页必须加
万一条数多了,页面直接卡死。Django自带Paginator:
from django.core.paginator import Paginator
def point_list(request):
records = PointRecord.objects.select_related('user').order_by('-created_at')
paginator = Paginator(records, 20) # 每页20条
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'points/list.html', {'page_obj': page_obj})
模板里加个分页导航就行。
3. 静态文件与部署
开发时Django自动托管静态文件,但生产环境必须用Nginx。我在上海租房,家里宽带上传慢,所以常用Gunicorn + Nginx部署到阿里云轻量服务器,月付60块搞定。
# 安装Gunicorn
pip install gunicorn
# 启动
gunicorn mysite.wsgi:application --bind 0.0.0.0:8000
配合Nginx反向代理,加个SSL证书(Let's Encrypt免费),一套下来不到两小时。
常见坑 & 面试题答案
这些年踩过的坑,总结成几道高频面试题:
| 问题 | 我的回答 |
|---|---|
| Django ORM怎么防止SQL注入? | 自动参数化查询,不用原生SQL就基本安全 |
| 如何处理并发积分扣减? | 用F表达式 + 事务,例如 PointRecord.objects.filter(user=user).update(balance=F('balance') - 10) |
| settings.py里的SECRET_KEY能放代码仓库吗? | 绝对不行!用环境变量或配置文件分离 |
| 为什么用Django不用Flask? | 快速交付场景下,Django的“全栈”特性减少集成成本 |
最后:外包程序员的生存之道
说到底,我们不是在写艺术,是在交活儿。Django之所以适合外包,是因为它让你少写代码、少背锅、快交付。至于区块链?等客户真愿意为技术买单再说吧。
上周三演示时,客户看着那个朴素的积分列表,居然点头说“有内味了”。我心想:这哪是区块链,这明明是“糊弄学+Django”的胜利。
不过话说回来,能用简单技术解决复杂问题,才是真本事。下次再有人问“Django过时了吗?”,你就反问:“你的需求,需要微服务+K8s+Service Mesh吗?”
如果不是,那就老老实实用Django,早点下班,回家打游戏。
附:我的VSCode Django开发插件清单(亲测好用)
- Python(官方)
- Django(Baptiste Darthenay)
- Pylance
- GitLens
- REST Client(测试API超方便)
- indent-rainbow(对齐强迫症福音)
就这样,希望这篇带点烟火气的教程,能帮你少熬几个夜。毕竟,在上海,房租那么贵,命得省着点用。

评论 0