从写爬虫到搭网站:一个考公程序员的Django初体验
上周五晚上十点半,我盯着 VSCode 里满屏的 Go 后端日志,突然意识到一个问题:我这个天天和算法、高并发打交道的“资深”后端码农,居然连个像样的个人网站都没有。
事情的起因其实有点搞笑。我们组最近在搞一个内部数据可视化项目,产品经理拍脑袋说:“要不咱们用 Django 搭个前端展示页面吧,Python 简单,你不是之前写过爬虫吗?”
我内心翻了个白眼——爬虫是爬虫,Web 是 Web,这能一样?但嘴上还是应了下来,毕竟离省考还有三个月,领导看我复习资料的眼神已经不太友善了,得表现得“积极工作”一点。
于是,抱着“速战速决,赶紧回去刷行测”的心态,我花了周末两天时间,硬是把人生第一个 Django 网站跑起来了。过程中踩了不少坑,也顺手整理了这篇记录,算是给未来的自己(以及同样想快速上手 Django 的兄弟)留个路标。
为啥是 Django?不是 Flask,也不是 Go?
先别急着喷我技术选型保守。其实在公司,我们的主力后端语言是 Go —— 高性能、并发强、部署轻量,非常适合我们这种每天要处理百万级请求的系统。但这次不一样:需求简单、交付快、还要兼容我那点 Python 老底子。
我大学时搞过一段时间爬虫,用的就是 Python + requests + BeautifulSoup,后来实习还写过基于 Scrapy 的分布式采集框架。所以对 Python 生态不算陌生。而 Django 作为“全栈式”Web 框架,自带 ORM、Admin、用户认证、路由系统,开箱即用,特别适合快速原型开发。
相比之下:
- Flask 太轻量,啥都要自己配,适合微服务,但不适合“赶工”;
- Go 的 Gin/Echo 虽然快,但 HTML 渲染、模板继承这些玩意儿写起来不如 Django 优雅;
- Node.js?算了,前端同事已经够卷了,我不想再碰 JS 生态。
所以,Django 成了最合理的选择——哪怕它被某些性能控嘲讽为“笨重”,但对我这个只想“搭个页面交差+顺便学点新东西”的在职考生来说,开发效率 > 极致性能。
环境搭建:VSCode + Django = 舒服!
作为一个 VSCode 死忠粉,插件装了一堆:Python、Pylance、Django、Bracket Pair Colorizer、GitLens……启动项目前,先确保环境干净:
# 创建虚拟环境(强烈建议!别污染全局)
python -m venv djangosite_env
source djangosite_env/bin/activate # Linux/Mac
# djangosite_env\Scripts\activate # Windows
# 安装 Django
pip install django
# 验证安装
django-admin --version # 输出类似 4.2.7
然后新建项目:
django-admin startproject mysite
cd mysite
python manage.py runserver
浏览器打开 http://127.0.0.1:8000,看到那个经典的火箭图标——成了!那一刻,我甚至有点感动,仿佛回到了大二第一次跑通 Hello World 的夜晚。
💡 小贴士:如果你用 VSCode,记得在
.vscode/settings.json里指定 Python 解释器路径,不然调试会出问题。我上次就是因为没设,debug 时一直报 ModuleNotFoundError,差点砸键盘。
从“Hello World”到真实业务:建个文章发布系统
光看默认页面当然不够。产品经理的需求其实是:“展示最近抓取的行业新闻”。这不就是我老本行——爬虫 + 展示?
第一步:设计模型(Model)
Django 的 ORM 真香!不用写 SQL,用 Python 类定义表结构:
# mysite/news/models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
source_url = models.URLField()
published_at = models.DateTimeField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
这里我加了 published_at(新闻发布时间)和 created_at(入库时间),方便后续排序。字段类型也很直观:CharField 对应 VARCHAR,TextField 是长文本,URLField 自带校验。
第二步:注册 Admin,手动录入测试数据
Django 自带的 Admin 后台简直是懒人福音:
# mysite/news/admin.py
from django.contrib import admin
from .models import Article
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'published_at', 'created_at')
search_fields = ('title',)
然后执行迁移:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser # 按提示输入用户名密码
启动服务后,访问 /admin,登录,就能看到一个功能完整的后台!我手动加了几条假数据,瞬间有了“产品上线”的错觉。
🤦♂️ 踩坑记录:第一次忘了执行
makemigrations,直接migrate,结果表没建。报错Table "news_article" does not exist。这种低级错误,在 deadline 压力下真的会发生!
写视图(View)和模板(Template):让数据动起来
现在要把数据库里的文章展示到首页。
视图函数
# mysite/news/views.py
from django.shortcuts import render
from .models import Article
def home(request):
articles = Article.objects.order_by('-published_at')[:10] # 最新10条
return render(request, 'news/home.html', {'articles': articles})
URL 路由
# mysite/news/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
]
别忘了在主 urls.py 里 include:
# mysite/mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('news.urls')),
]
模板渲染
Django 模板语法简洁明了:
<!-- mysite/news/templates/news/home.html -->
<!DOCTYPE html>
<html>
<head>
<title>行业快讯</title>
</head>
<body>
<h1>最新文章</h1>
{% for article in articles %}
<div>
<h2>{{ article.title }}</h2>
<p>{{ article.content|truncatewords:30 }}</p>
<small>发布时间: {{ article.published_at }}</small>
<a href="{{ article.source_url }}">原文链接</a>
</div>
<hr>
{% empty %}
<p>暂无文章</p>
{% endfor %}
</body>
</html>
刷新页面,数据出来了!那一刻,我真的笑出了声——虽然只是个静态列表,但这是我亲手搭建的第一个完整 Web 应用。
性能优化?先别急,但得有意识
作为对性能敏感的后端程序员,我忍不住想:如果文章量涨到 10 万条,Article.objects.all() 会不会把 DB 干崩?
Django 提供了多种优化手段:
| 优化方式 | 说明 | 适用场景 |
|---|---|---|
select_related |
一对一/外键预加载 | 减少 N+1 查询 |
prefetch_related |
多对多/反向关系预加载 | 关联查询优化 |
分页 (Paginator) |
避免一次性加载大量数据 | 列表页必备 |
| 数据库索引 | 在 published_at 上加索引 |
加速排序和过滤 |
比如,加索引:
class Article(models.Model):
# ...
published_at = models.DateTimeField(db_index=True) # 关键!
再比如分页:
from django.core.paginator import Paginator
def home(request):
article_list = Article.objects.order_by('-published_at')
paginator = Paginator(article_list, 10) # 每页10条
page_number = request.GET.get('page')
articles = paginator.get_page(page_number)
return render(request, 'news/home.html', {'articles': articles})
这些改动成本极低,但能极大提升可扩展性。写代码时多想一步,线上就少一次 P0 事故——这是我们组长常说的话。
和爬虫联动:自动化填充数据
既然我擅长爬虫,那就写个脚本自动抓数据入库!
# scripts/fetch_news.py
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
django.setup()
from news.models import Article
import requests
from bs4 import BeautifulSoup
from datetime import datetime
def scrape_and_save():
url = "https://example-news-site.com"
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')
for item in soup.select('.news-item'):
title = item.select_one('.title').text
content = item.select_one('.content').text
link = item.select_one('a')['href']
# 避免重复
if not Article.objects.filter(source_url=link).exists():
Article.objects.create(
title=title,
content=content,
source_url=link,
published_at=datetime.now()
)
if __name__ == "__main__":
scrape_and_save()
然后用 crontab 定时执行:
# 每天上午9点抓一次
0 9 * * * /path/to/venv/bin/python /path/to/scripts/fetch_news.py
完美!现在我的小网站不仅能展示数据,还能自动更新。虽然比不上公司里用 Kafka + Flink 的实时管道,但对个人项目来说,够用了。
为什么我这个 Go 后端要学 Django?
可能有人会问:你不是准备考公吗?干嘛还折腾这些?
原因有三:
- 技术广度:公务员考试中的“计算机专业知识”部分,Web 开发是重点。理解 MVC、HTTP、数据库交互,比死记硬背概念有用得多。
- 简历加分:哪怕上岸了,技术背景也是优势。很多政务系统正在数字化,懂前后端的人才吃香。
- 保持手感:每天刷题很枯燥,写点代码能调节心态。而且 Django 的开发体验真的很治愈——那种“所想即所得”的流畅感,是 Go 里写 middleware 和 context 时体会不到的。
当然,我也清楚 Django 不适合所有场景。如果未来要做高并发 API 网关、实时推荐引擎,肯定还是 Go + Redis + Kafka 更合适。但在快速验证想法、搭建 MVP、做数据展示这类任务上,Django 依然是王者。
写在最后:从程序员到准公务员的跨界思考
搭完这个网站,我突然意识到:无论是写算法、调 Go 服务、写爬虫,还是现在玩 Django,核心能力其实是相通的——解决问题的逻辑 + 快速学习的能力。
考公路上,很多人劝我“别碰代码了,专心背书”。但我偏不。因为我知道,真正的竞争力,从来不是单一技能,而是跨界整合的能力。
下周我就要去参加行测模考了。但今晚,我决定再给这个小网站加个搜索功能——用 Django 的 icontains 实现全文检索。毕竟,梦想还是要有的,万一上岸后被分到信息中心,还能用上呢?
作者:某大厂后端程序员,白天调优 Go 服务,晚上刷行测真题,周末研究 Django。目标:2024年省考上岸。
GitHub:懒得放(怕被同事发现我在摸鱼)
本文所有代码均在本地测试通过,生产环境请务必加缓存、限流、日志监控——别学我,我可是被运维追着骂过的人 😅

评论 0